Skip to content

Recognize custom file extensions #3230

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -257,10 +257,13 @@ public static ICompilationUnit getFakeCompilationUnit(String uri) {
}

static ICompilationUnit getFakeCompilationUnit(URI uri, IProgressMonitor monitor) {
if (uri == null || !"file".equals(uri.getScheme()) || !uri.getPath().endsWith(".java")) {
if (uri == null || !"file".equals(uri.getScheme())) {
return null;
}
java.nio.file.Path path = Paths.get(uri);
if (!isJavaFile(path)) {
return null;
}
//Only support existing standalone java files
if (!java.nio.file.Files.isReadable(path)) {
return null;
Expand All @@ -275,7 +278,7 @@ static ICompilationUnit getFakeCompilationUnit(URI uri, IProgressMonitor monitor
IProject project = JavaLanguageServerPlugin.getProjectsManager().getDefaultProject();
if (project == null || !project.isAccessible()) {
String fileName = path.getFileName().toString();
if (fileName.endsWith(".java") || fileName.endsWith(".class")) {
if (isJavaFile(fileName) || fileName.endsWith(".class")) {
fileName = fileName.substring(0, fileName.lastIndexOf('.'));
}
WorkingCopyOwner owner = new WorkingCopyOwner() {
Expand Down Expand Up @@ -657,6 +660,23 @@ private boolean find(IJavaElement element, final ASTNode[] nodes, SimpleName nod
}
}

public static boolean isJavaFile(java.nio.file.Path path) {
try {
return path != null && isJavaFile(path.toFile().getName());
} catch (Exception e) {
JavaLanguageServerPlugin.logException(e.getMessage(), e);
}
return false;
}

public static boolean isJavaFile(IPath path) {
return path != null && isJavaFile(path.lastSegment());
}

public static boolean isJavaFile(String name) {
return name != null && org.eclipse.jdt.internal.core.util.Util.isJavaLikeFileName(name);
}

/**
* Enumeration for determining the location of a Java element. Either returns
* with the name range only, or the extended source range around the name of the
Expand Down Expand Up @@ -1095,7 +1115,7 @@ public static IFile findFile(String uriString) {
}

public static ISchedulingRule getRule(String uri) {
IResource resource = JDTUtils.findFile(uri);
IResource resource = findFile(uri);
if (resource != null) {
return ResourcesPlugin.getWorkspace().getRuleFactory().createRule(resource);
}
Expand Down Expand Up @@ -1749,7 +1769,7 @@ public static List<Location> searchDecompiledSources(IJavaElement element, IClas
}
Location location;
if (node != null) {
String uriString = JDTUtils.toUri(classFile);
String uriString = toUri(classFile);
IDocument document = new Document(contents);
if (declaration) {
int offset = node.getStartPosition();
Expand Down Expand Up @@ -1793,7 +1813,7 @@ public static List<Location> searchDecompiledSources(IJavaElement element, IClas
locations.add(location);
}
} else {
location = JDTUtils.toLocation(classFile, 0, 0);
location = toLocation(classFile, 0, 0);
locations.add(location);
}
} finally {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.ls.core.internal.ActionableNotification;
import org.eclipse.jdt.ls.core.internal.JDTUtils;
import org.eclipse.jdt.ls.core.internal.JavaClientConnection.JavaLanguageClient;
import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin;
import org.eclipse.jdt.ls.core.internal.ProgressReport;
Expand Down Expand Up @@ -94,7 +95,7 @@ public void onDidProjectsImported(IProgressMonitor monitor) {
JavaLanguageServerPlugin.getProjectsManager().getConnection().sendActionableNotification(notification);
}
}

/**
* Find all the Protobuf source output directories of the given project.
* @param project project.
Expand Down Expand Up @@ -133,7 +134,7 @@ private boolean containsJavaFiles(Set<File> generatedDirectories) {

try (Stream<Path> walkStream = Files.walk(dir.toPath())) {
boolean containsJavaFile = walkStream.filter(p -> p.toFile().isFile()).anyMatch(f -> {
return f.toString().endsWith(".java");
return JDTUtils.isJavaFile(f);
});

if (containsJavaFile) {
Expand Down Expand Up @@ -194,7 +195,7 @@ private static void runGenerateProtobufTasks(String projectName, IProgressMonito
try {
build.get().withConnection(connection -> {
connection.newBuild().forTasks("generateProto", "generateTestProto").run();
return null;
return null;
}, monitor);
} catch (Exception e) {
JavaLanguageServerPlugin.logException(e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,9 @@ public static void handleFileRenameForTypeDeclaration(String documentUri) {
IProblem renameProblem = desiredProblem.get();
String newName = renameProblem.getArguments()[1];
String oldName = cu.getElementName();
String newUri = documentUri.replace(oldName, newName + ".java");
int index = oldName.lastIndexOf(".");
String extension = index > 0 ? oldName.substring(index) : ".java";
String newUri = documentUri.replace(oldName, newName + extension);
WorkspaceEdit edit = new WorkspaceEdit(List.of(Either.forRight(new RenameFile(documentUri, newUri))));
edit.setChanges(Collections.emptyMap());
final boolean applyNow = JavaLanguageServerPlugin.getPreferencesManager().getClientPreferences().isWorkspaceApplyEditSupported();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,18 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.content.IContentType;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
import org.eclipse.jdt.ls.core.internal.IConstants;
import org.eclipse.jdt.ls.core.internal.JSONUtility;
import org.eclipse.jdt.ls.core.internal.JVMConfigurator;
Expand Down Expand Up @@ -57,7 +62,6 @@ public BaseInitHandler(ProjectsManager projectsManager, PreferenceManager prefer
this.projectsManager = projectsManager;
}

@SuppressWarnings("unchecked")
public InitializeResult initialize(InitializeParams param) {
logInfo("Initializing Java Language Server " + JavaLanguageServerPlugin.getVersion());
InitializeResult result = new InitializeResult();
Expand All @@ -70,6 +74,7 @@ public InitializeResult initialize(InitializeParams param) {
return result;
}

@SuppressWarnings("unchecked")
public Map<?, ?> handleInitializationOptions(InitializeParams param) {
Map<?, ?> initializationOptions = this.getInitializationOptions(param);
Map<String, Object> extendedClientCapabilities = getInitializationOption(initializationOptions, "extendedClientCapabilities", Map.class);
Expand Down Expand Up @@ -109,7 +114,6 @@ public InitializeResult initialize(InitializeParams param) {
rootPaths.add(workspaceLocation);
}
if (initializationOptions.get(SETTINGS_KEY) instanceof Map<?, ?> settings) {
@SuppressWarnings("unchecked")
Preferences prefs = Preferences.createFrom((Map<String, Object>) settings);
prefs.setRootPaths(rootPaths);
preferenceManager.update(prefs);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ private static boolean isFileNameRenameEvent(FileRename event) {
}

return (oldPath.toFile().isFile() || newPath.toFile().isFile())
&& oldPath.lastSegment().endsWith(".java") && newPath.lastSegment().endsWith(".java")
&& JDTUtils.isJavaFile(oldPath.lastSegment()) && JDTUtils.isJavaFile(newPath.lastSegment())
&& Objects.equals(oldPath.removeLastSegments(1), newPath.removeLastSegments(1));
}

Expand All @@ -331,7 +331,7 @@ private static boolean isMoveEvent(FileRename event) {
return false;
}

return oldPath.toFile().isFile() && oldPath.lastSegment().endsWith(".java")
return oldPath.toFile().isFile() && JDTUtils.isJavaFile(oldPath.lastSegment())
&& Objects.equals(oldPath.lastSegment(), newPath.lastSegment());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ private void cleanUpDiagnostics(String uri) {

private void discardWorkingCopies(String parentUri) {
IPath parentPath = ResourceUtils.filePathFromURI(parentUri);
if (parentPath != null && !parentPath.lastSegment().endsWith(".java")) {
if (parentPath != null && !JDTUtils.isJavaFile(parentPath)) {
ICompilationUnit[] workingCopies = JavaCore.getWorkingCopies(null);
for (ICompilationUnit workingCopy : workingCopies) {
IResource resource = workingCopy.getResource();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,7 @@ private static File findNearbyNonEmptyFile(File nioFile) throws IOException {
try (Stream<java.nio.file.Path> walk = Files.walk(directory, 1)) {
Optional<java.nio.file.Path> found = walk.filter(Files::isRegularFile).filter(file -> {
try {
return file.toString().endsWith(".java") && !Objects.equals(nioFile.getName(), file.toFile().getName()) && Files.size(file) > 0;
return JDTUtils.isJavaFile(file) && !Objects.equals(nioFile.getName(), file.toFile().getName()) && Files.size(file) > 0;
} catch (IOException e) {
return false;
}
Expand Down Expand Up @@ -672,7 +672,7 @@ public FileVisitResult preVisitDirectory(java.nio.file.Path dirPath, BasicFileAt
return FileVisitResult.TERMINATE;
}

if (javaFile == null && f.getName().endsWith(".java")) {
if (javaFile == null && JDTUtils.isJavaFile(f.getName())) {
javaFile = f;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,11 @@
*******************************************************************************/
package org.eclipse.jdt.ls.core.internal.preferences;

import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.LinkedHashMap;
import java.util.List;
Expand All @@ -28,13 +26,13 @@
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.core.runtime.content.IContentType;
import org.eclipse.core.runtime.preferences.DefaultScope;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.InstanceScope;
Expand All @@ -43,6 +41,7 @@
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.manipulation.CodeStyleConfiguration;
import org.eclipse.jdt.core.manipulation.JavaManipulation;
import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
import org.eclipse.jdt.internal.core.manipulation.CodeTemplateContextType;
import org.eclipse.jdt.internal.core.manipulation.CodeTemplateContextType.CodeTemplateVariableResolver;
import org.eclipse.jdt.internal.core.manipulation.JavaManipulationMessages;
Expand All @@ -54,7 +53,6 @@
import org.eclipse.jdt.internal.corext.util.CodeFormatterUtil;
import org.eclipse.jdt.ls.core.internal.IConstants;
import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin;
import org.eclipse.jdt.ls.core.internal.ProjectUtils;
import org.eclipse.jdt.ls.core.internal.ResourceUtils;
import org.eclipse.jdt.ls.core.internal.StatusFactory;
import org.eclipse.jdt.ls.core.internal.handlers.BaseDiagnosticsHandler;
Expand Down Expand Up @@ -258,6 +256,49 @@ public void update(Preferences preferences) {
JavaLanguageServerPlugin.getInstance().getClientConnection().publishDiagnostics(diagnostics);
}
}
if (!oldPreferences.getFilesAssociations().equals(preferences.getFilesAssociations())) {
configureContentTypes(preferences);
}
}

// only for test purpose
public static void configureContentTypes(Preferences preferences) {
if (preferences != null && preferences.getFilesAssociations() != null) {
IContentType javaSourceContentType = Platform.getContentTypeManager().getContentType(JavaCore.JAVA_SOURCE_CONTENT_TYPE);
if (javaSourceContentType != null) {
List<String> toRemove = new ArrayList<>();
String[] specs = javaSourceContentType.getFileSpecs(IContentType.FILE_EXTENSION_SPEC);
for (String spec : specs) {
if (!SuffixConstants.EXTENSION_java.equals(spec)) {
toRemove.add(spec);
}
}
List<String> toAdd = new ArrayList<>();
for (String spec : preferences.getFilesAssociations()) {
if (toRemove.contains(spec)) {
toRemove.remove(spec);
} else {
toAdd.add(spec);
}
}
for (String spec : toRemove) {
try {
javaSourceContentType.removeFileSpec(spec, IContentType.FILE_EXTENSION_SPEC);
} catch (CoreException e) {
JavaLanguageServerPlugin.logException(e);
}
}
for (String spec : toAdd) {
try {
javaSourceContentType.addFileSpec(spec, IContentType.FILE_EXTENSION_SPEC);
} catch (CoreException e) {
JavaLanguageServerPlugin.logException(e);
}
}
} else {
JavaLanguageServerPlugin.logInfo("There is no java source content type.");
}
}
}

private void preferencesChanged(Preferences oldPreferences, Preferences newPreferences) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,11 @@ public class Preferences {
* Tab Size
*/
public static final String JAVA_CONFIGURATION_TABSIZE = "java.format.tabSize";

/**
* Files associations to languages
*/
public static final String JAVA_CONFIGURATION_ASSOCIATIONS = "java.associations";
/**
* Specifies Java Execution Environments.
*/
Expand Down Expand Up @@ -589,6 +594,7 @@ public class Preferences {
private static Map<String, List<String>> nonnullClasspathStorage = new HashMap<>();
private static Map<String, List<String>> nullableClasspathStorage = new HashMap<>();
private static Map<String, List<String>> nonnullbydefaultClasspathStorage = new HashMap<>();
private List<String> filesAssociations = new ArrayList<>();

private Map<String, Object> configuration;
private Severity incompleteClasspathSeverity;
Expand Down Expand Up @@ -1330,9 +1336,36 @@ public static Preferences createFrom(Map<String, Object> configuration) {
prefs.setChainCompletionEnabled(chainCompletionEnabled);
List<String> diagnosticFilter = getList(configuration, JAVA_DIAGNOSTIC_FILER, Collections.emptyList());
prefs.setDiagnosticFilter(diagnosticFilter);
Object object = getValue(configuration, JAVA_CONFIGURATION_ASSOCIATIONS);
Set<String> associations = new HashSet<>();
if (object instanceof Map map) {
try {
Map<String, String> element = map;
element.forEach((k, v) -> {
// Java LS only support a small subset of the glob pattern syntax (*.xxx)
if ("java".equals(v) && validateFilePattern(k)) {
associations.add(k.substring(2));
}
});
} catch (Exception e) {
JavaLanguageServerPlugin.logException(e);
}
}
prefs.setFilesAssociations(new ArrayList<>(associations));
return prefs;
}

private static boolean validateFilePattern(String filename) {
if (filename != null && filename.startsWith("*.") && filename.length() > 2) {
String ext = filename.substring(2);
if (!ext.contains("?") && !ext.contains("*")) {
return true;
}
}
JavaLanguageServerPlugin.logInfo("Pattern '" + filename + "' is not supported.");
return false;
}

/**
* Sets the new value of the enabled clean ups.
*
Expand Down Expand Up @@ -2582,4 +2615,12 @@ public List<String> getDiagnosticFilter() {
public void setDiagnosticFilter(List<String> diagnosticFilter) {
this.diagnosticFilter = diagnosticFilter;
}

public List<String> getFilesAssociations() {
return filesAssociations;
}

public void setFilesAssociations(List<String> filesAssociations) {
this.filesAssociations = filesAssociations;
}
}
Loading
Loading