6
6
import java .util .List ;
7
7
import java .util .Objects ;
8
8
import java .util .Set ;
9
+ import java .util .concurrent .atomic .AtomicInteger ;
9
10
import java .util .regex .Matcher ;
10
11
import java .util .regex .Pattern ;
11
12
import java .util .regex .PatternSyntaxException ;
12
13
13
14
import org .jetbrains .annotations .NotNull ;
14
15
16
+ import com .intellij .openapi .application .ReadAction ;
17
+ import com .intellij .openapi .application .WriteAction ;
15
18
import com .intellij .openapi .diagnostic .Logger ;
16
19
import com .intellij .openapi .editor .Document ;
17
20
import com .intellij .openapi .fileEditor .FileDocumentManager ;
21
+ import com .intellij .openapi .progress .ProgressIndicator ;
18
22
import com .intellij .openapi .project .Project ;
19
23
import com .intellij .openapi .roots .ProjectRootManager ;
24
+ import com .intellij .openapi .util .ThrowableComputable ;
20
25
import com .intellij .psi .PsiDocumentManager ;
21
26
import com .intellij .psi .PsiFile ;
27
+ import com .intellij .util .ApplicationKt ;
22
28
import com .intellij .util .PsiErrorElementUtil ;
29
+ import com .intellij .util .ThrowableRunnable ;
23
30
24
31
import software .xdev .saveactions .core .ExecutionMode ;
25
32
import software .xdev .saveactions .core .service .SaveActionsService ;
@@ -62,7 +69,9 @@ public Engine(
62
69
this .mode = mode ;
63
70
}
64
71
65
- public void processPsiFilesIfNecessary ()
72
+ public void processPsiFilesIfNecessary (
73
+ @ NotNull final ProgressIndicator indicator ,
74
+ final boolean async )
66
75
{
67
76
if (this .psiFiles == null )
68
77
{
@@ -73,36 +82,112 @@ public void processPsiFilesIfNecessary()
73
82
LOGGER .info (String .format ("Action \" %s\" not enabled on %s" , this .activation .getText (), this .project ));
74
83
return ;
75
84
}
85
+
86
+ indicator .setIndeterminate (true );
87
+ final Set <PsiFile > psiFilesEligible = this .getEligiblePsiFiles (indicator , async );
88
+ if (psiFilesEligible .isEmpty ())
89
+ {
90
+ LOGGER .info ("No files are eligible" );
91
+ return ;
92
+ }
93
+
94
+ final List <SaveCommand > processorsEligible = this .getEligibleProcessors (indicator , psiFilesEligible );
95
+ if (processorsEligible .isEmpty ())
96
+ {
97
+ LOGGER .info ("No processors are eligible" );
98
+ return ;
99
+ }
100
+
101
+ this .flushPsiFiles (indicator , async , psiFilesEligible );
102
+
103
+ this .execute (indicator , processorsEligible , psiFilesEligible );
104
+ }
105
+
106
+ private Set <PsiFile > getEligiblePsiFiles (final @ NotNull ProgressIndicator indicator , final boolean async )
107
+ {
76
108
LOGGER .info (String .format ("Processing %s files %s mode %s" , this .project , this .psiFiles , this .mode ));
77
- final Set <PsiFile > psiFilesEligible = this .psiFiles .stream ()
78
- .filter (psiFile -> this .isPsiFileEligible (this .project , psiFile ))
79
- .collect (toSet ());
109
+ indicator .checkCanceled ();
110
+ indicator .setText2 ("Collecting files to process" );
111
+
112
+ final ThrowableComputable <Set <PsiFile >, RuntimeException > psiFilesEligibleFunc =
113
+ () -> this .psiFiles .stream ()
114
+ .filter (psiFile -> this .isPsiFileEligible (this .project , psiFile ))
115
+ .collect (toSet ());
116
+ final Set <PsiFile > psiFilesEligible = async
117
+ ? ReadAction .compute (psiFilesEligibleFunc )
118
+ : psiFilesEligibleFunc .compute ();
80
119
LOGGER .info (String .format ("Valid files %s" , psiFilesEligible ));
81
- this . processPsiFiles ( this . project , psiFilesEligible , this . mode ) ;
120
+ return psiFilesEligible ;
82
121
}
83
122
84
- private void processPsiFiles (final Project project , final Set <PsiFile > psiFiles , final ExecutionMode mode )
123
+ private @ NotNull List <SaveCommand > getEligibleProcessors (
124
+ final @ NotNull ProgressIndicator indicator ,
125
+ final Set <PsiFile > psiFilesEligible )
85
126
{
86
- if (psiFiles .isEmpty ())
87
- {
88
- return ;
89
- }
90
127
LOGGER .info (String .format ("Start processors (%d)" , this .processors .size ()));
128
+ indicator .checkCanceled ();
129
+ indicator .setText2 ("Collecting processors" );
130
+
91
131
final List <SaveCommand > processorsEligible = this .processors .stream ()
92
- .map (processor -> processor .getSaveCommand (project , psiFiles ))
132
+ .map (processor -> processor .getSaveCommand (this . project , psiFilesEligible ))
93
133
.filter (command -> this .storage .isEnabled (command .getAction ()))
94
- .filter (command -> command .getModes ().contains (mode ))
134
+ .filter (command -> command .getModes ().contains (this . mode ))
95
135
.toList ();
96
136
LOGGER .info (String .format ("Filtered processors %s" , processorsEligible ));
97
- if (!processorsEligible .isEmpty ())
137
+ return processorsEligible ;
138
+ }
139
+
140
+ private void flushPsiFiles (
141
+ final @ NotNull ProgressIndicator indicator ,
142
+ final boolean async ,
143
+ final Set <PsiFile > psiFilesEligible )
144
+ {
145
+ LOGGER .info (String .format ("Flushing files (%d)" , psiFilesEligible .size ()));
146
+ indicator .checkCanceled ();
147
+ indicator .setText2 ("Flushing files" );
148
+
149
+ final ThrowableRunnable <RuntimeException > flushFilesFunc = () -> {
150
+ final PsiDocumentManager psiDocumentManager = PsiDocumentManager .getInstance (this .project );
151
+ psiFilesEligible .forEach (psiFile -> this .commitDocumentAndSave (psiFile , psiDocumentManager ));
152
+ };
153
+ if (async )
154
+ {
155
+ ApplicationKt .getApplication ().invokeAndWait (() -> WriteAction .run (flushFilesFunc ));
156
+ }
157
+ else
98
158
{
99
- final PsiDocumentManager psiDocumentManager = PsiDocumentManager .getInstance (project );
100
- psiFiles .forEach (psiFile -> this .commitDocumentAndSave (psiFile , psiDocumentManager ));
159
+ flushFilesFunc .run ();
101
160
}
102
- final List <SimpleEntry <Action , Result <ResultCode >>> results = processorsEligible .stream ()
161
+ }
162
+
163
+ private void execute (
164
+ final @ NotNull ProgressIndicator indicator ,
165
+ final List <SaveCommand > processorsEligible ,
166
+ final Set <PsiFile > psiFilesEligible )
167
+ {
168
+ indicator .checkCanceled ();
169
+ indicator .setIndeterminate (false );
170
+ indicator .setFraction (0d );
171
+
172
+ final List <SaveCommand > saveCommands = processorsEligible .stream ()
103
173
.filter (Objects ::nonNull )
104
- .peek (command -> LOGGER .info (String .format ("Execute command %s on %d files" , command , psiFiles .size ())))
105
- .map (command -> new SimpleEntry <>(command .getAction (), command .execute ()))
174
+ .toList ();
175
+
176
+ final AtomicInteger executedCount = new AtomicInteger ();
177
+ final List <SimpleEntry <Action , Result <ResultCode >>> results = saveCommands .stream ()
178
+ .map (command -> {
179
+ LOGGER .info (String .format ("Execute command %s on %d files" , command , psiFilesEligible .size ()));
180
+
181
+ indicator .checkCanceled ();
182
+ indicator .setText2 ("Executing '" + command .getAction ().getText () + "'" );
183
+
184
+ final SimpleEntry <Action , Result <ResultCode >> entry =
185
+ new SimpleEntry <>(command .getAction (), command .execute ());
186
+
187
+ indicator .setFraction ((double )executedCount .incrementAndGet () / saveCommands .size ());
188
+
189
+ return entry ;
190
+ })
106
191
.toList ();
107
192
LOGGER .info (String .format ("Exit engine with results %s" , results .stream ()
108
193
.map (entry -> entry .getKey () + ":" + entry .getValue ())
0 commit comments