5
5
*/
6
6
package io .flutter .sdk ;
7
7
8
+ import com .google .gson .JsonArray ;
9
+ import com .google .gson .JsonElement ;
10
+ import com .google .gson .JsonObject ;
8
11
import com .intellij .ProjectTopics ;
9
12
import com .intellij .openapi .application .ApplicationManager ;
10
13
import com .intellij .openapi .application .ModalityState ;
13
16
import com .intellij .openapi .roots .ModuleRootEvent ;
14
17
import com .intellij .openapi .roots .ModuleRootListener ;
15
18
import com .intellij .openapi .roots .libraries .PersistentLibraryKind ;
19
+ import com .intellij .openapi .util .SystemInfo ;
20
+ import com .intellij .openapi .util .io .FileUtil ;
21
+ import com .intellij .openapi .util .text .StringUtil ;
16
22
import com .intellij .openapi .vfs .*;
23
+ import com .intellij .util .io .URLUtil ;
17
24
import com .jetbrains .lang .dart .util .DotPackagesFileUtil ;
18
25
import io .flutter .pub .PubRoot ;
19
26
import io .flutter .pub .PubRoots ;
27
+ import io .flutter .utils .JsonUtils ;
20
28
import org .jetbrains .annotations .NotNull ;
29
+ import org .jetbrains .annotations .Nullable ;
21
30
22
- import java .util .HashSet ;
23
- import java .util .List ;
24
- import java .util .Map ;
25
- import java .util .Set ;
31
+ import java .io .IOException ;
32
+ import java .nio .charset .StandardCharsets ;
33
+ import java .util .*;
26
34
import java .util .concurrent .atomic .AtomicBoolean ;
27
35
28
36
import static com .jetbrains .lang .dart .util .PubspecYamlUtil .PUBSPEC_YAML ;
@@ -123,15 +131,23 @@ private static Set<String> getFlutterPluginPaths(List<PubRoot> roots) {
123
131
final Set <String > paths = new HashSet <>();
124
132
125
133
for (PubRoot pubRoot : roots ) {
134
+
135
+ final Map <String , String > map ;
126
136
if (pubRoot .getPackagesFile () == null ) {
127
- continue ;
137
+ @ Nullable VirtualFile configFile = pubRoot .getPackageConfigFile ();
138
+ if (configFile == null ) {
139
+ continue ;
140
+ }
141
+ // TODO(messick) Use the code in the Dart plugin when available.
142
+ // This is just a backup in case we need it. It does not have a proper cache, but the Dart plugin does.
143
+ map = loadPackagesMap (configFile );
128
144
}
129
-
130
- final Map <String , String > map = DotPackagesFileUtil .getPackagesMap (pubRoot .getPackagesFile ());
131
- if (map == null ) {
132
- continue ;
145
+ else {
146
+ map = DotPackagesFileUtil .getPackagesMap (pubRoot .getPackagesFile ());
147
+ if (map == null ) {
148
+ continue ;
149
+ }
133
150
}
134
-
135
151
for (String packagePath : map .values ()) {
136
152
final VirtualFile libFolder = LocalFileSystem .getInstance ().findFileByPath (packagePath );
137
153
if (libFolder == null ) {
@@ -150,4 +166,53 @@ private static Set<String> getFlutterPluginPaths(List<PubRoot> roots) {
150
166
151
167
return paths ;
152
168
}
169
+
170
+ private static Map <String , String > loadPackagesMap (@ NotNull VirtualFile root ) {
171
+ Map <String , String > result = new HashMap <>();
172
+ try {
173
+ JsonElement element = JsonUtils .parseString (new String (root .contentsToByteArray (), StandardCharsets .UTF_8 ));
174
+ if (element != null ) {
175
+ JsonElement packages = element .getAsJsonObject ().get ("packages" );
176
+ if (packages != null ) {
177
+ JsonArray array = packages .getAsJsonArray ();
178
+ for (int i = 0 ; i < array .size (); i ++) {
179
+ JsonObject pkg = array .get (i ).getAsJsonObject ();
180
+ String name = pkg .get ("name" ).getAsString ();
181
+ String rootUri = pkg .get ("rootUri" ).getAsString ();
182
+ if (name != null && rootUri != null ) {
183
+ // need to protect '+' chars because URLDecoder.decode replaces '+' with space
184
+ final String encodedUriWithoutPluses = StringUtil .replace (rootUri , "+" , "%2B" );
185
+ final String uri = URLUtil .decode (encodedUriWithoutPluses );
186
+ final String packageUri = getAbsolutePackageRootPath (root .getParent ().getParent (), uri );
187
+ result .put (name , packageUri );
188
+ }
189
+ }
190
+ }
191
+ }
192
+ }
193
+ catch (IOException ignored ) {
194
+ }
195
+ return result ;
196
+ }
197
+
198
+ @ Nullable
199
+ private static String getAbsolutePackageRootPath (@ NotNull final VirtualFile baseDir , @ NotNull final String uri ) {
200
+ // Copied from the Dart plugin.
201
+ if (uri .startsWith ("file:/" )) {
202
+ final String pathAfterSlashes = StringUtil .trimEnd (StringUtil .trimLeading (StringUtil .trimStart (uri , "file:/" ), '/' ), "/" );
203
+ if (SystemInfo .isWindows && !ApplicationManager .getApplication ().isUnitTestMode ()) {
204
+ if (pathAfterSlashes .length () > 2 && Character .isLetter (pathAfterSlashes .charAt (0 )) && ':' == pathAfterSlashes .charAt (1 )) {
205
+ return pathAfterSlashes ;
206
+ }
207
+ }
208
+ else {
209
+ return "/" + pathAfterSlashes ;
210
+ }
211
+ }
212
+ else {
213
+ return FileUtil .toCanonicalPath (baseDir .getPath () + "/" + uri );
214
+ }
215
+
216
+ return null ;
217
+ }
153
218
}
0 commit comments