52f2f47f39a8b8b8b07e3aa380d58518ce0abfb5
[idea/community.git] / platform / core-api / src / com / intellij / util / PathUtil.java
1 // Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2 package com.intellij.util;
3
4 import com.intellij.openapi.application.PathManager;
5 import com.intellij.openapi.util.NlsSafe;
6 import com.intellij.openapi.util.SystemInfo;
7 import com.intellij.openapi.util.io.FileUtil;
8 import com.intellij.openapi.util.io.FileUtilRt;
9 import com.intellij.openapi.util.text.StringUtil;
10 import com.intellij.openapi.vfs.LocalFileProvider;
11 import com.intellij.openapi.vfs.VirtualFile;
12 import com.intellij.openapi.vfs.VirtualFileManager;
13 import com.intellij.openapi.vfs.VirtualFileSystem;
14 import com.intellij.util.io.URLUtil;
15 import org.jetbrains.annotations.*;
16
17 import java.util.ArrayList;
18 import java.util.List;
19
20 public final class PathUtil {
21   private PathUtil() { }
22
23   @Nullable
24   public static String getLocalPath(@Nullable VirtualFile file) {
25     if (file == null || !file.isValid()) {
26       return null;
27     }
28     if (file.getFileSystem().getProtocol().equals(URLUtil.JAR_PROTOCOL) && file.getParent() != null) {
29       return null;
30     }
31     return getLocalPath(file.getPath());
32   }
33
34   @NotNull
35   public static String getLocalPath(@NotNull String path) {
36     return FileUtil.toSystemDependentName(StringUtil.trimEnd(path, URLUtil.JAR_SEPARATOR));
37   }
38
39   @NotNull
40   public static String getJarPathForClass(@NotNull Class<?> aClass) {
41     final String pathForClass = PathManager.getJarPathForClass(aClass);
42     assert pathForClass != null : aClass;
43     return pathForClass;
44   }
45
46   @NotNull
47   public static @NlsSafe String toPresentableUrl(@NotNull String url) {
48     return getLocalPath(VirtualFileManager.extractPath(url));
49   }
50
51   /**
52    * @deprecated Use {@link FileUtil#toCanonicalPath(String)}
53    */
54   @Deprecated
55   public static String getCanonicalPath(@NonNls String path) {
56     return FileUtil.toCanonicalPath(path);
57   }
58
59   @NotNull
60   public static String getFileName(@NotNull String path) {
61     return PathUtilRt.getFileName(path);
62   }
63
64   @Nullable
65   public static String getFileExtension(@NotNull String name) {
66     return PathUtilRt.getFileExtension(name);
67   }
68
69   @NotNull
70   public static String getParentPath(@NotNull String path) {
71     return PathUtilRt.getParentPath(path);
72   }
73
74   @NotNull
75   public static String suggestFileName(@NotNull String text) {
76     return PathUtilRt.suggestFileName(text);
77   }
78
79   @NotNull
80   public static String suggestFileName(@NotNull String text, final boolean allowDots, final boolean allowSpaces) {
81     return PathUtilRt.suggestFileName(text, allowDots, allowSpaces);
82   }
83
84   public static boolean isValidFileName(@NotNull String fileName) {
85     return PathUtilRt.isValidFileName(fileName, true);
86   }
87
88   public static boolean isValidFileName(@NotNull String fileName, boolean strict) {
89     return PathUtilRt.isValidFileName(fileName, strict);
90   }
91
92   @Contract("null -> null; !null -> !null")
93   public static String toSystemIndependentName(@Nullable String path) {
94     return path == null ? null : FileUtilRt.toSystemIndependentName(path);
95   }
96
97   @Contract("null -> null; !null -> !null")
98   public static String toSystemDependentName(@Nullable String path) {
99     return path == null ? null : FileUtilRt.toSystemDependentName(path);
100   }
101
102   @NotNull
103   public static String driveLetterToLowerCase(@NotNull String path) {
104     if (SystemInfo.isWindows && FileUtil.isWindowsAbsolutePath(path) && Character.isUpperCase(path.charAt(0))) {
105       return Character.toLowerCase(path.charAt(0)) + path.substring(1);
106     }
107     return path;
108   }
109
110   @NotNull
111   public static String makeFileName(@NotNull String name, @Nullable String extension) {
112     return StringUtil.isEmpty(extension) ? name : name + '.' + extension;
113   }
114
115   /**
116    * @return true if the {@code file} path is equal to the {@code path},
117    * according to the file's parent directories case sensitivity.
118    */
119   public static boolean pathEqualsTo(@NotNull VirtualFile file, @NotNull @SystemIndependent String path) {
120     path = FileUtil.toCanonicalPath(path);
121     int li = path.length();
122     while (file != null && li != -1) {
123       int i = path.lastIndexOf('/', li-1);
124       CharSequence fileName = file.getNameSequence();
125       if (StringUtil.endsWithChar(fileName, '/')) {
126         fileName = fileName.subSequence(0, fileName.length()-1);
127       }
128       if (!StringUtil.equal(fileName, path.substring(i + 1, li), file.isCaseSensitive())) {
129         return false;
130       }
131       file = file.getParent();
132       li = i;
133     }
134     return li == -1 && file == null;
135   }
136
137   private static @NotNull List<VirtualFile> getHierarchy(@NotNull VirtualFile file) {
138     List<VirtualFile> result = new ArrayList<>();
139     while (file != null) {
140       result.add(file);
141       file = file.getParent();
142     }
143     return result;
144   }
145
146   public static boolean isAncestorOrSelf(@NotNull @SystemIndependent String ancestorPath, @NotNull VirtualFile file) {
147     ancestorPath = FileUtil.toCanonicalPath(ancestorPath);
148     List<VirtualFile> hierarchy = getHierarchy(file);
149     if (ancestorPath.isEmpty()) {
150       return true;
151     }
152     int i = 0;
153     boolean result = false;
154     int j;
155     for (j = hierarchy.size() - 1; j >= 0; j--) {
156       VirtualFile part = hierarchy.get(j);
157       String name = part.getName();
158       boolean matches = part.isCaseSensitive() ? StringUtil.startsWith(ancestorPath, i, name) :
159                         StringUtil.startsWithIgnoreCase(ancestorPath, i, name);
160       if (!matches) {
161         break;
162       }
163       i += name.length();
164       if (!name.endsWith("/")) {
165         if (i != ancestorPath.length() && ancestorPath.charAt(i) != '/') {
166           break;
167         }
168         i++;
169       }
170       if (i >= ancestorPath.length()) {
171         result = true;
172         break;
173       }
174     }
175     return result;
176   }
177
178   //<editor-fold desc="Deprecated stuff.">
179   /** @deprecated use {@link com.intellij.openapi.vfs.VfsUtil#getLocalFile(VirtualFile)} instead */
180   @Deprecated
181   @ApiStatus.ScheduledForRemoval(inVersion = "2021.1")
182   @NotNull
183   public static VirtualFile getLocalFile(@NotNull VirtualFile file) {
184     if (file.isValid()) {
185       VirtualFileSystem fileSystem = file.getFileSystem();
186       if (fileSystem instanceof LocalFileProvider) {
187         VirtualFile localFile = ((LocalFileProvider)fileSystem).getLocalVirtualFileFor(file);
188         if (localFile != null) {
189           return localFile;
190         }
191       }
192     }
193
194     return file;
195   }
196   //</editor-fold>
197 }