Skip to content

Commit

Permalink
feat: Check if project is a MicroProfile, Qute, etc project to map file
Browse files Browse the repository at this point in the history
with a language server

Fixes #1185

Signed-off-by: azerr <[email protected]>
  • Loading branch information
angelozerr committed Oct 1, 2023
1 parent 2be23ca commit 2cf4479
Show file tree
Hide file tree
Showing 15 changed files with 210 additions and 36 deletions.
Original file line number Diff line number Diff line change
@@ -1,14 +1,26 @@
package com.redhat.devtools.intellij.lsp4ij;

import com.intellij.lang.Language;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;

import javax.annotation.Nonnull;
import java.util.AbstractMap;

public class ContentTypeToLanguageServerDefinition extends AbstractMap.SimpleEntry<Language, LanguageServersRegistry.LanguageServerDefinition> {
public ContentTypeToLanguageServerDefinition(@Nonnull Language language,
@Nonnull LanguageServersRegistry.LanguageServerDefinition provider) {

private final DocumentMatcher documentMatcher;

public ContentTypeToLanguageServerDefinition(@NotNull Language language,
@NotNull LanguageServersRegistry.LanguageServerDefinition provider,
@NotNull DocumentMatcher documentMatcher) {
super(language, provider);
this.documentMatcher = documentMatcher;
}

public boolean match(VirtualFile file, Project project) {
return documentMatcher.match(file, project);
}

public boolean isEnabled() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.redhat.devtools.intellij.lsp4ij;

import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;

public interface DocumentMatcher {

boolean match(VirtualFile file, Project project);

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@

import com.intellij.openapi.extensions.AbstractExtensionPointBean;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.serviceContainer.BaseKeyedLazyInstance;
import com.intellij.util.xmlb.annotations.Attribute;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public class LanguageMappingExtensionPointBean extends BaseKeyedLazyInstance<DocumentMatcher> {

private static final DocumentMatcher DEFAULT_DOCUMENT_MATCHER = (file,project) -> true;

public class LanguageMappingExtensionPointBean extends AbstractExtensionPointBean {
public static final ExtensionPointName<LanguageMappingExtensionPointBean> EP_NAME = ExtensionPointName.create("com.redhat.devtools.intellij.quarkus.languageMapping");

@Attribute("id")
Expand All @@ -15,4 +21,21 @@ public class LanguageMappingExtensionPointBean extends AbstractExtensionPointBea

@Attribute("serverId")
public String serverId;

@Attribute("documentMatcher")
public String documentMatcher;

public @NotNull DocumentMatcher getDocumentMatcher() {
try {
return super.getInstance();
}
catch(Exception e) {
return DEFAULT_DOCUMENT_MATCHER;
}
}

@Override
protected @Nullable String getImplementationClassName() {
return documentMatcher;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.eclipse.lsp4j.jsonrpc.Launcher;
import org.eclipse.lsp4j.jsonrpc.validation.NonNull;
import org.eclipse.lsp4j.services.LanguageServer;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -194,7 +195,7 @@ private void initialize() {
for (LanguageMappingExtensionPointBean extension : LanguageMappingExtensionPointBean.EP_NAME.getExtensions()) {
Language language = Language.findLanguageByID(extension.language);
if (language != null) {
languageMappings.add(new LanguageMapping(language, extension.id, extension.serverId));
languageMappings.add(new LanguageMapping(language, extension.id, extension.serverId, extension.getDocumentMatcher()));
}
}

Expand All @@ -205,7 +206,7 @@ private void initialize() {
for (LanguageMapping mapping : languageMappings) {
LanguageServerDefinition lsDefinition = servers.get(mapping.languageId);
if (lsDefinition != null) {
registerAssociation(mapping.language, lsDefinition, mapping.languageId);
registerAssociation(lsDefinition, mapping);
} else {
LOGGER.warn("server '" + mapping.id + "' not available"); //$NON-NLS-1$ //$NON-NLS-2$
}
Expand All @@ -230,13 +231,14 @@ List<ContentTypeToLanguageServerDefinition> findProviderFor(final @NonNull Langu
}


public void registerAssociation(@Nonnull Language language,
@Nonnull LanguageServerDefinition serverDefinition, @Nullable String languageId) {
public void registerAssociation(@NotNull LanguageServerDefinition serverDefinition, @Nullable LanguageMapping mapping) {
@NotNull Language language = mapping.language;
@Nullable String languageId = mapping.languageId;
if (languageId != null) {
serverDefinition.registerAssociation(language, languageId);
}

connections.add(new ContentTypeToLanguageServerDefinition(language, serverDefinition));
connections.add(new ContentTypeToLanguageServerDefinition(language, serverDefinition, mapping.getDocumentMatcher()));
}

public List<ContentTypeToLanguageServerDefinition> getContentTypeToLSPExtensions() {
Expand All @@ -258,39 +260,46 @@ LanguageServerDefinition getDefinition(@NonNull String languageServerId) {
*/
private static class LanguageMapping {

@Nonnull
@NotNull
public final String id;
@Nonnull
@NotNull
public final Language language;
@Nullable
public final String languageId;

public LanguageMapping(@Nonnull Language language, @Nonnull String id, @Nullable String languageId) {
private final DocumentMatcher documentMatcher;

public LanguageMapping(@NotNull Language language, @Nullable String id, @Nullable String languageId, @NotNull DocumentMatcher documentMatcher) {
this.language = language;
this.id = id;
this.languageId = languageId;
this.documentMatcher = documentMatcher;
}

public DocumentMatcher getDocumentMatcher() {
return documentMatcher;
}
}

/**
* @param file
* @param serverDefinition
* @return whether the given serverDefinition is suitable for the file
*/
public boolean matches(@Nonnull VirtualFile file, @NonNull LanguageServerDefinition serverDefinition,
Project project) {
return getAvailableLSFor(LSPIJUtils.getFileLanguage(file, project)).contains(serverDefinition);
}

/**
* @param document
* @param serverDefinition
* @return whether the given serverDefinition is suitable for the file
*/
public boolean matches(@Nonnull Document document, @Nonnull LanguageServerDefinition serverDefinition,
Project project) {
return getAvailableLSFor(LSPIJUtils.getDocumentLanguage(document, project)).contains(serverDefinition);
public boolean matches(VirtualFile file,
Project project, @Nonnull LanguageServerDefinition serverDefinition) {
Language language = LSPIJUtils.getFileLanguage(file, project);
if (language == null) {
return false;
}
for (ContentTypeToLanguageServerDefinition mapping : this.connections) {
if (language.isKindOf(mapping.getKey()) && serverDefinition.equals(mapping.getValue())) {
if (mapping.match(file, project)) {
return true;
}
}
}
return false;
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ private Collection<LanguageServerWrapper> getLSWrappers(@NotNull VirtualFile fil
res.addAll(startedServers.stream()
.filter(wrapper -> {
try {
return wrapper.isEnabled() && (wrapper.isConnectedTo(path) || LanguageServersRegistry.getInstance().matches(file, wrapper.serverDefinition, project));
return wrapper.isEnabled() && (wrapper.isConnectedTo(path) || LanguageServersRegistry.getInstance().matches(file, project, wrapper.serverDefinition));
} catch (ProcessCanceledException cancellation) {
throw cancellation;
} catch (Exception e) {
Expand Down Expand Up @@ -195,9 +195,11 @@ private Collection<LanguageServerWrapper> getLSWrappers(@NotNull VirtualFile fil
}
final Project fileProject = file != null ? LSPIJUtils.getProject(file) : null;
if (fileProject != null) {
LanguageServerWrapper wrapper = new LanguageServerWrapper(fileProject, serverDefinition);
startedServers.add(wrapper);
res.add(wrapper);
if(mapping.match(file, fileProject)) {
LanguageServerWrapper wrapper = new LanguageServerWrapper(fileProject, serverDefinition);
startedServers.add(wrapper);
res.add(wrapper);
}
}
}
processedContentTypes.add(contentType);
Expand Down Expand Up @@ -247,7 +249,7 @@ private Collection<LanguageServerWrapper> getMatchingStartedWrappers(@NotNull Vi
@Nullable Predicate<ServerCapabilities> request) {
synchronized (startedServers) {
return startedServers.stream().filter(wrapper -> wrapper.isConnectedTo(LSPIJUtils.toUri(file))
|| (LanguageServersRegistry.getInstance().matches(file, wrapper.serverDefinition, project)
|| (LanguageServersRegistry.getInstance().matches(file, project, wrapper.serverDefinition)
&& wrapper.canOperate(LSPIJUtils.getProject(file)))).filter(wrapper -> request == null
|| (wrapper.getServerCapabilities() == null || request.test(wrapper.getServerCapabilities())))
.collect(Collectors.toList());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.redhat.devtools.intellij.quarkus.lsp;

import com.intellij.openapi.editor.Document;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.redhat.devtools.intellij.lsp4ij.DocumentMatcher;
import com.redhat.devtools.intellij.lsp4ij.LSPIJUtils;
import com.redhat.devtools.intellij.quarkus.QuarkusModuleUtil;
import com.redhat.devtools.intellij.qute.psi.utils.PsiQuteProjectUtils;

public class AbstractQuarkusDocumentMatcher implements DocumentMatcher {
@Override
public boolean match(VirtualFile file, Project fileProject) {
Module module = LSPIJUtils.getModule(file);
return module != null && QuarkusModuleUtil.isQuarkusModule(module);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.redhat.devtools.intellij.quarkus.lsp;

import com.intellij.openapi.editor.Document;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.redhat.devtools.intellij.lsp4ij.LSPIJUtils;
import com.redhat.devtools.intellij.quarkus.QuarkusModuleUtil;

public class QuarkusDocumentMatcherForJavaFile extends AbstractQuarkusDocumentMatcher {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.redhat.devtools.intellij.quarkus.lsp;

import com.intellij.openapi.editor.Document;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.redhat.devtools.intellij.quarkus.QuarkusModuleUtil;

public class QuarkusDocumentMatcherForPropertiesFile extends AbstractQuarkusDocumentMatcher {

@Override
public boolean match(VirtualFile file, Project fileProject) {
if (!matchFile(file, fileProject)) {
return false;
}
return super.match(file, fileProject);
}

private boolean matchFile(VirtualFile file, Project fileProject) {
return QuarkusModuleUtil.isQuarkusPropertiesFile(file, fileProject) || QuarkusModuleUtil.isQuarkusYAMLFile(file, fileProject);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import static com.redhat.devtools.intellij.qute.psi.utils.PsiQuteProjectUtils.isQuteTemplate;

/**
* Qute language substitutor to force some language file (ex:HTML, YAML, etc) to "_Qute" language when:
* <ul>
Expand All @@ -34,7 +36,7 @@
*/
public class QuteLanguageSubstitutor extends LanguageSubstitutor {
protected boolean isTemplate(VirtualFile file, Module module) {
return file.getPath().contains("templates") &&
return isQuteTemplate(file, module) &&
ModuleRootManager.getInstance(module).getFileIndex().isInSourceContent(file);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.redhat.devtools.intellij.qute.lsp;

import com.intellij.openapi.editor.Document;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.redhat.devtools.intellij.lsp4ij.DocumentMatcher;
import com.redhat.devtools.intellij.lsp4ij.LSPIJUtils;
import com.redhat.devtools.intellij.qute.psi.utils.PsiQuteProjectUtils;

public class AbstractQuteDocumentMatcher implements DocumentMatcher {

@Override
public boolean match(VirtualFile file, Project fileProject) {
Module module = LSPIJUtils.getModule(file);
return module != null && PsiQuteProjectUtils.hasQuteSupport(module);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.redhat.devtools.intellij.qute.lsp;

import com.intellij.openapi.editor.Document;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.redhat.devtools.intellij.lsp4ij.DocumentMatcher;
import com.redhat.devtools.intellij.lsp4ij.LSPIJUtils;
import com.redhat.devtools.intellij.quarkus.QuarkusModuleUtil;

public class QuteDocumentMatcherForJavaFile extends AbstractQuteDocumentMatcher {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.redhat.devtools.intellij.qute.lsp;

import com.intellij.openapi.editor.Document;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.redhat.devtools.intellij.lsp4ij.LSPIJUtils;
import com.redhat.devtools.intellij.qute.psi.utils.PsiQuteProjectUtils;

import static com.redhat.devtools.intellij.qute.psi.utils.PsiQuteProjectUtils.isQuteTemplate;

public class QuteDocumentMatcherForTemplateFile extends AbstractQuteDocumentMatcher {

@Override
public boolean match(VirtualFile file, Project fileProject) {
if (!super.match(file, fileProject)) {
return false;
}
return isQuteTemplate(file, LSPIJUtils.getModule(file));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.redhat.devtools.intellij.quarkus.QuarkusModuleUtil;
import com.redhat.devtools.intellij.lsp4ij.LSPIJUtils;
import com.redhat.devtools.intellij.qute.psi.internal.QuteJavaConstants;
Expand Down Expand Up @@ -121,4 +123,9 @@ public static void appendAndSlash(@NotNull StringBuilder path, @NotNull String s
path.append('/');
}
}

public static boolean isQuteTemplate(VirtualFile file, Module module) {
return file.getPath().contains("templates") &&
ModuleRootManager.getInstance(module).getFileIndex().isInSourceContent(file);
}
}
12 changes: 8 additions & 4 deletions src/main/resources/META-INF/lsp4ij-quarkus.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<idea-plugin>
<extensions defaultExtensionNs="com.redhat.devtools.intellij.quarkus">
<!-- Quarkus LSP -->
<server id="quarkus"
<server id="microprofile"
label="Tools for MicroProfile"
class="com.redhat.devtools.intellij.quarkus.lsp.QuarkusServer"
clientImpl="com.redhat.devtools.intellij.quarkus.lsp.QuarkusLanguageClient"
Expand All @@ -17,9 +17,13 @@
]]>
</description>
</server>
<languageMapping language="Properties" serverId="quarkus"/>
<languageMapping language="JAVA" serverId="quarkus"/>
<serverIconProvider serverId="quarkus" class="com.redhat.devtools.intellij.microprofile.lang.MicroProfileServerIconProvider" />
<languageMapping language="Properties"
serverId="microprofile"
documentMatcher="com.redhat.devtools.intellij.quarkus.lsp.QuarkusDocumentMatcherForPropertiesFile" />
<languageMapping language="JAVA"
serverId="microprofile"
documentMatcher="com.redhat.devtools.intellij.quarkus.lsp.QuarkusDocumentMatcherForJavaFile"/>
<serverIconProvider serverId="microprofile" class="com.redhat.devtools.intellij.microprofile.lang.MicroProfileServerIconProvider" />
</extensions>

<extensions defaultExtensionNs="com.intellij">
Expand Down
Loading

0 comments on commit 2cf4479

Please sign in to comment.