11package com .github .lppedd .cc .angular2 ;
22
3+ import java .util .ArrayList ;
34import java .util .Arrays ;
45import java .util .Collection ;
5- import java .util .HashSet ;
6+ import java .util .Comparator ;
67import java .util .List ;
78import java .util .stream .Collectors ;
89
9- import org .angular2 .lang .Angular2LangUtil ;
10+ import org .angular2 .entities .Angular2EntitiesProvider ;
11+ import org .angular2 .entities .Angular2Entity ;
12+ import org .angular2 .entities .Angular2Module ;
13+ import org .angular2 .index .Angular2IndexingHandler ;
14+ import org .angular2 .index .Angular2SourceModuleIndex ;
1015import org .jetbrains .annotations .NotNull ;
1116import org .jetbrains .annotations .Nullable ;
1217
1318import com .github .lppedd .cc .api .CommitScopeProvider ;
1419import com .github .lppedd .cc .api .ProviderPresentation ;
20+ import com .intellij .codeInsight .documentation .DocumentationManager ;
21+ import com .intellij .lang .javascript .psi .JSImplicitElementProvider ;
1522import com .intellij .openapi .application .Application ;
1623import com .intellij .openapi .application .ApplicationManager ;
1724import com .intellij .openapi .project .Project ;
1825import com .intellij .openapi .util .Computable ;
19- import com .intellij .openapi .vfs .VirtualFile ;
20- import com .intellij .psi .search .FilenameIndex ;
26+ import com .intellij .psi .PsiElement ;
2127import com .intellij .psi .search .GlobalSearchScope ;
22- import com .intellij .util .Processor ;
23- import com .intellij .util .indexing .IdFilter ;
28+ import com .intellij .psi .stubs .StubIndex ;
29+ import com .intellij .psi .util .CachedValueProvider .Result ;
30+ import com .intellij .psi .util .CachedValuesManager ;
31+ import com .intellij .psi .util .PsiModificationTracker ;
32+ import com .intellij .util .containers .ContainerUtil ;
2433
2534/**
2635 * @author Edoardo Luppi
@@ -33,10 +42,14 @@ class Angular2CommitScopeProvider implements CommitScopeProvider {
3342 );
3443
3544 private static final Application APPLICATION = ApplicationManager .getApplication ();
45+ private static final StubIndex STUB_INDEX = StubIndex .getInstance ();
46+
3647 private final Project project ;
48+ private final CachedValuesManager cachedValuesManager ;
3749
38- Angular2CommitScopeProvider (@ NotNull final Project project ) {
50+ Angular2CommitScopeProvider (final Project project ) {
3951 this .project = project ;
52+ cachedValuesManager = CachedValuesManager .getManager (project );
4053 }
4154
4255 @ NotNull
@@ -54,56 +67,61 @@ public ProviderPresentation getPresentation() {
5467 @ NotNull
5568 @ Override
5669 public List <CommitScope > getCommitScopes (@ Nullable final String commitType ) {
57- return "build" .equals (commitType ) ? SCOPES : findNgModules ();
70+ return "build" .equals (commitType ) ? SCOPES : findModules ();
71+ }
72+
73+ @ NotNull
74+ private List <CommitScope > findModules () {
75+ return cachedValuesManager .getCachedValue (project , this ::computeCommitScopes );
5876 }
5977
6078 @ NotNull
61- private List <CommitScope > findNgModules () {
62- final Collection <String > fileNames = new HashSet <>(64 );
63-
64- final Processor <String > stringProcessor = fileName -> {
65- if (fileName .toLowerCase ().endsWith (".module.ts" )) {
66- fileNames .add (fileName );
67- }
68-
69- return true ;
70- };
71-
72- final GlobalSearchScope projectScope = GlobalSearchScope .projectScope (project );
73-
74- APPLICATION .runReadAction (() ->
75- FilenameIndex .processAllFileNames (
76- stringProcessor ,
77- projectScope ,
78- IdFilter .getProjectIdFilter (project , false )
79- )
80- );
81-
82- return fileNames
83- .stream ()
84- .flatMap (fileName ->
85- APPLICATION .runReadAction ((Computable <Collection <VirtualFile >>) () ->
86- FilenameIndex .getVirtualFilesByName (
87- project ,
88- fileName ,
89- true ,
90- projectScope
91- )
92- ).stream ()
93- )
94- .filter (this ::isAngular2Context )
95- .map (VirtualFile ::getName )
96- .map (String ::toLowerCase )
97- .map (fileName -> fileName .replaceFirst (".module.ts$" , "" ))
98- .sorted ()
99- .map (moduleName -> new Angular2CommitScope (moduleName , null ))
100- .collect (Collectors .toList ());
79+ private Result <List <CommitScope >> computeCommitScopes () {
80+ final List <CommitScope > commitScopes =
81+ APPLICATION .runReadAction ((Computable <List <CommitScope >>) () ->
82+ findSourceModules ()
83+ .stream ()
84+ .map (this ::toCommitScope )
85+ .sorted (Comparator .comparing (CommitScope ::getText ))
86+ .collect (Collectors .toList ())
87+ );
88+
89+ return Result .create (commitScopes , PsiModificationTracker .MODIFICATION_COUNT );
10190 }
10291
103- private boolean isAngular2Context (@ NotNull final VirtualFile virtualFile ) {
104- return APPLICATION .runReadAction (
105- (Computable <Boolean >) () -> Angular2LangUtil .isAngular2Context (project , virtualFile )
106- );
92+ /** Returns the local project's {@code NgModule}s, without externally provided ones. */
93+ @ NotNull
94+ private Collection <Angular2Module > findSourceModules () {
95+ final Collection <Angular2Module > modules = new ArrayList <>(32 );
96+ STUB_INDEX .processElements (
97+ Angular2SourceModuleIndex .KEY ,
98+ Angular2IndexingHandler .NG_MODULE_INDEX_NAME ,
99+ project ,
100+ GlobalSearchScope .projectScope (project ),
101+ JSImplicitElementProvider .class ,
102+ module -> {
103+ if (module .isValid ()) {
104+ ContainerUtil .addIfNotNull (modules , Angular2EntitiesProvider .getModule (module ));
105+ }
106+
107+ return true ;
108+ });
109+
110+ return modules ;
111+ }
112+
113+ /**
114+ * Transforms a {@code NgModule} definition to a {@link CommitScope}.<br />
115+ * If a JSDoc comment is found, it is used as scope description.
116+ */
117+ @ NotNull
118+ private CommitScope toCommitScope (@ NotNull final Angular2Entity module ) {
119+ final PsiElement sourceElement = module .getTypeScriptClass ();
120+ final String name = CCAngularUtils .toDashCase (module .getName ()).replaceFirst ("-module$" , "" );
121+ final String documentation =
122+ DocumentationManager .getProviderFromElement (sourceElement )
123+ .generateDoc (sourceElement , null );
124+ return new Angular2CommitScope (name , documentation );
107125 }
108126
109127 private static class Angular2CommitBuildScope extends CommitScope {
0 commit comments