mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
File filtering implementation a'la .gitignore
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
// Copyright 2000-2018 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.
|
||||
package com.intellij.formatting.fileSet;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Describes a set of files specified by a directory and/or by a file mask.
|
||||
* <p>
|
||||
* Examples:
|
||||
* <ul>
|
||||
* <li>
|
||||
* {@code *.test}<br>
|
||||
* A file ending with .test in any directory
|
||||
* </li>
|
||||
* <li>
|
||||
* {@code /foo/*.test}<br>
|
||||
* A file with *.test extension immediately under <i>project-dir</i>/foo directory.
|
||||
* </li>
|
||||
* <li>
|
||||
* {@code foo/*.test}<br>
|
||||
* A file with .test extension if their parent directory is "foo", equivalent to /**/foo/*.test
|
||||
* </li>
|
||||
* <li>
|
||||
* {@code /*.test}
|
||||
* A file with .test extension directly under project root directory.
|
||||
* </li>
|
||||
* </ul>
|
||||
*/
|
||||
public class FileSetEntry {
|
||||
|
||||
private @Nullable Pattern myPathPattern;
|
||||
private @Nullable Pattern myFileNamePattern;
|
||||
|
||||
public FileSetEntry(@NotNull String spec) {
|
||||
compileSpec(spec);
|
||||
}
|
||||
|
||||
private void compileSpec(@NotNull String spec) {
|
||||
String pathSpec = "";
|
||||
String fileSpec;
|
||||
int lastSlashPos = spec.lastIndexOf('/');
|
||||
if (lastSlashPos >= 0) {
|
||||
fileSpec = spec.substring(lastSlashPos + 1);
|
||||
pathSpec = spec.substring(0, lastSlashPos + 1);
|
||||
if (pathSpec.length() > 0 && pathSpec.charAt(0) != '/') {
|
||||
pathSpec = "/**/" + pathSpec;
|
||||
}
|
||||
}
|
||||
else {
|
||||
fileSpec = spec;
|
||||
}
|
||||
if (!pathSpec.isEmpty()) {
|
||||
myPathPattern = Pattern.compile(specToRegexp(pathSpec, true));
|
||||
}
|
||||
if (!fileSpec.isEmpty()) {
|
||||
myFileNamePattern = Pattern.compile(specToRegexp(fileSpec, false));
|
||||
}
|
||||
}
|
||||
|
||||
private static String specToRegexp(@NotNull String spec, boolean isPathSpec) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
char[] chars = spec.toCharArray();
|
||||
int i = 0;
|
||||
while (i < chars.length) {
|
||||
char c = chars[i];
|
||||
switch (c) {
|
||||
case '*':
|
||||
if (isPathSpec && i < chars.length - 1 && chars[i + 1] == '*') {
|
||||
sb.append("([^/]*/)*");
|
||||
i++;
|
||||
if (i < chars.length - 1 && chars[i + 1] == '/') {
|
||||
i ++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
sb.append("[^/]*");
|
||||
}
|
||||
break;
|
||||
case '?':
|
||||
sb.append("[^/]");
|
||||
break;
|
||||
default:
|
||||
if (isRegexSpecialChar(c)) {
|
||||
sb.append('\\').append(c);
|
||||
}
|
||||
else {
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
i ++;
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
private static boolean isRegexSpecialChar(char c) {
|
||||
return "^${}[]().*+-&".indexOf(c) >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the file set entry matches the given virtual file.
|
||||
*
|
||||
* @param project The current project.
|
||||
* @param virtualFile The virtual file to check against.
|
||||
* @return True if there is a match, false otherwise.
|
||||
*/
|
||||
public boolean matches(@NotNull Project project, @NotNull VirtualFile virtualFile) {
|
||||
if (myFileNamePattern == null && myPathPattern == null) return false; // Empty spec matches nothing
|
||||
String name = virtualFile.getName();
|
||||
VirtualFile parent = virtualFile.getParent();
|
||||
String path = getRelativePath(project, parent) + "/";
|
||||
return patternMatches(myPathPattern, path) && patternMatches(myFileNamePattern, name);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String getRelativePath(@NotNull Project project, @Nullable VirtualFile parent) {
|
||||
VirtualFile projectDir = project.getBaseDir();
|
||||
String projectPath = projectDir.getPath();
|
||||
if (parent != null) {
|
||||
String parentPath = parent.getPath();
|
||||
if (parentPath.startsWith(projectPath)) {
|
||||
return parentPath.substring(projectPath.length());
|
||||
}
|
||||
else {
|
||||
return parentPath;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private static boolean patternMatches(@Nullable Pattern pattern, @NotNull String str) {
|
||||
return pattern == null || pattern.matcher(str).matches();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
// Copyright 2000-2018 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.
|
||||
package com.intellij.formatting.fileSet;
|
||||
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.testFramework.PlatformTestCase;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class FileSetEntryTest extends PlatformTestCase {
|
||||
|
||||
public void testSimpleFileMask() {
|
||||
FileSetEntry entry = new FileSetEntry("*.java");
|
||||
assertTrue(entry.matches(getProject(), createFile("src/test.java")));
|
||||
assertFalse(entry.matches(getProject(), createFile("src/test.txt")));
|
||||
assertTrue(entry.matches(getProject(), createFile("file3.java")));
|
||||
}
|
||||
|
||||
public void testFileMaskWithDir() {
|
||||
FileSetEntry entry = new FileSetEntry("/src/*.java");
|
||||
assertTrue(entry.matches(getProject(), createFile("src/test.java")));
|
||||
assertFalse(entry.matches(getProject(), createFile("src/test.txt")));
|
||||
assertFalse(entry.matches(getProject(), createFile("file3.java")));
|
||||
}
|
||||
|
||||
public void testExtendedDirSpec() {
|
||||
FileSetEntry entry = new FileSetEntry("/src/**/test/*.java");
|
||||
assertTrue(entry.matches(getProject(), createFile("src/test/file1.java")));
|
||||
assertTrue(entry.matches(getProject(), createFile("src/dir1/test/file1.java")));
|
||||
assertTrue(entry.matches(getProject(), createFile("src/dir1/dir2/test/file1.java")));
|
||||
assertFalse(entry.matches(getProject(), createFile("src/dir1/dir2/test/dir3/file1.java")));
|
||||
FileSetEntry entry2 = new FileSetEntry("/src/**/test/**/*.java");
|
||||
assertTrue(entry2.matches(getProject(), createFile("src/test/a/file1.java")));
|
||||
assertTrue(entry2.matches(getProject(), createFile("src/b/test/a/file1.java")));
|
||||
}
|
||||
|
||||
public void testAnyCharMarks() {
|
||||
FileSetEntry entry = new FileSetEntry("/test-??/**/test?.java");
|
||||
assertFalse(entry.matches(getProject(), createFile("test-1/test2.java")));
|
||||
assertTrue(entry.matches(getProject(), createFile("test-12/test3.java")));
|
||||
assertTrue(entry.matches(getProject(), createFile("test-12/test/testa.java")));
|
||||
}
|
||||
|
||||
|
||||
public void testRelativeDirTest() {
|
||||
FileSetEntry entry = new FileSetEntry("test/*.java");
|
||||
assertTrue(entry.matches(getProject(), createFile("src/test/file1.java")));
|
||||
assertTrue(entry.matches(getProject(), createFile("test/file2.java")));
|
||||
assertTrue(entry.matches(getProject(), createFile("a/b/c/d/test/file3.java")));
|
||||
}
|
||||
|
||||
private VirtualFile createFile(@NotNull String path) {
|
||||
String[] dirNames = path.split("/");
|
||||
VirtualFile baseDir = getProject().getBaseDir();
|
||||
for (int i = 0; i < dirNames.length - 1; i ++) {
|
||||
VirtualFile existing = VfsUtilCore.findRelativeFile(dirNames[i], baseDir);
|
||||
if (existing == null) {
|
||||
baseDir = createChildDirectory(baseDir, dirNames[i]);
|
||||
}
|
||||
else {
|
||||
baseDir = existing;
|
||||
}
|
||||
}
|
||||
return createChildData(baseDir, dirNames[dirNames.length - 1]);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user