Skip to content

Commit

Permalink
feat: Initialize roq support
Browse files Browse the repository at this point in the history
Signed-off-by: azerr <[email protected]>
  • Loading branch information
angelozerr committed Nov 6, 2024
1 parent 972c3a0 commit 257245e
Show file tree
Hide file tree
Showing 17 changed files with 830 additions and 183 deletions.
4 changes: 2 additions & 2 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ gradleVersion=8.6
channel=nightly
quarkusVersion=3.15.1
lsp4mpVersion=0.13.0
quarkusLsVersion=0.20.0
quteLsVersion=0.20.0
quarkusLsVersion=0.21.0-SNAPSHOT
quteLsVersion=0.21.0-SNAPSHOT
# Opt-out flag for bundling Kotlin standard library -> https://jb.gg/intellij-platform-kotlin-stdlib
kotlin.stdlib.default.dependency=false
# Enable Gradle Configuration Cache -> https://docs.gradle.org/current/userguide/configuration_cache.html
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,13 @@
* </ul>
*/
public class QuteLanguageSubstitutor extends LanguageSubstitutor {
protected boolean isTemplate(VirtualFile file, Module module) {
return isQuteTemplate(file, module) &&
ModuleRootManager.getInstance(module).getFileIndex().isInSourceContent(file);

private static boolean isTemplate(VirtualFile file, Module module) {
return isQuteTemplate(file, module) /*&&
ModuleRootManager.getInstance(module).getFileIndex().isInSourceContent(file)*/;
}

protected boolean isQuteModule(Module module) {
private static boolean isQuteModule(Module module) {
OrderEnumerator libraries = ModuleRootManager.getInstance(module).orderEntries().librariesOnly();
return libraries.process(new RootPolicy<Boolean>() {
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
*******************************************************************************/
package com.redhat.devtools.intellij.qute.psi.internal;

import java.util.Collection;
import java.util.List;

/**
* Qute Java constants.
*
Expand All @@ -30,6 +33,8 @@ public class QuteJavaConstants {

public static final String TEMPLATE_INSTANCE_INTERFACE = "io.quarkus.qute.TemplateInstance";

public static Collection<String> QUTE_MAVEN_COORDS = List.of("io.quarkus:quarkus-qute", "io.quarkus.qute:qute-core");

public static final String ENGINE_BUILDER_CLASS = "io.quarkus.qute.EngineBuilder";

public static final String VALUE_ANNOTATION_NAME = "value";
Expand Down Expand Up @@ -64,6 +69,8 @@ public class QuteJavaConstants {

public static final String TEMPLATE_EXTENSION_ANNOTATION_MATCH_NAME = "matchName";

public static final String TEMPLATE_EXTENSION_ANNOTATION_MATCH_NAMES = "matchNames";

// @TemplateData

public static final String TEMPLATE_DATA_ANNOTATION = "io.quarkus.qute.TemplateData";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*******************************************************************************
* Copyright (c) 2024 Red Hat Inc. and others.
* All rights reserved. This program and the accompanying materials
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat Inc. - initial API and implementation
*******************************************************************************/
package com.redhat.devtools.intellij.qute.psi.internal.extensions.roq;

import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.psi.PsiAnnotation;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.redhat.devtools.intellij.qute.psi.template.datamodel.AbstractAnnotationTypeReferenceDataModelProvider;
import com.redhat.devtools.intellij.qute.psi.template.datamodel.SearchContext;
import com.redhat.devtools.intellij.qute.psi.utils.AnnotationUtils;
import com.redhat.qute.commons.datamodel.resolvers.ValueResolverInfo;
import com.redhat.qute.commons.datamodel.resolvers.ValueResolverKind;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.Nullable;

import java.util.List;
import java.util.logging.Logger;

import static com.redhat.devtools.intellij.qute.psi.internal.QuteJavaConstants.VALUE_ANNOTATION_NAME;
import static com.redhat.devtools.intellij.qute.psi.internal.extensions.roq.RoqJavaConstants.DATA_MAPPING_ANNOTATION;

/**
* Roq @DataMapping annotation support.
*
* @author Angelo ZERR
*/
public class DataMappingSupport extends AbstractAnnotationTypeReferenceDataModelProvider {

private static final Logger LOGGER = Logger.getLogger(DataMappingSupport.class.getName());

private static final String INJECT_NAMESPACE = "inject";

private static final String[] ANNOTATION_NAMES = {DATA_MAPPING_ANNOTATION};

@Override
protected String[] getAnnotationNames() {
return ANNOTATION_NAMES;
}

@Override
protected void processAnnotation(PsiElement javaElement, PsiAnnotation annotation, String annotationName,
SearchContext context, ProgressIndicator monitor) {
if (!(javaElement instanceof PsiClass)) {
return;
}
// @DataMapping(value = "events", parentArray = true)
// public record Events(List<Event> list) {
// becomes --> inject:events

PsiClass type = (PsiClass) javaElement;
String value = getDataMappingAnnotationValue(type);
if (StringUtils.isNoneBlank(value)) {
collectResolversForInject(type, value, context.getDataModelProject().getValueResolvers());
}
}

@Nullable
private static String getDataMappingAnnotationValue(PsiClass javaElement) {
PsiAnnotation namedAnnotation = AnnotationUtils.getAnnotation(javaElement,
DATA_MAPPING_ANNOTATION);
if (namedAnnotation != null) {
return AnnotationUtils.getAnnotationMemberValue(namedAnnotation, VALUE_ANNOTATION_NAME);
}
return null;
}

private static void collectResolversForInject(PsiClass type, String named, List<ValueResolverInfo> resolvers) {
ValueResolverInfo resolver = new ValueResolverInfo();
resolver.setNamed(named);
resolver.setSourceType(type.getQualifiedName());
resolver.setSignature(type.getQualifiedName());
resolver.setNamespace(INJECT_NAMESPACE);
resolver.setKind(ValueResolverKind.InjectedBean);
resolvers.add(resolver);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*******************************************************************************
* Copyright (c) 2024 Red Hat Inc. and others.
* All rights reserved. This program and the accompanying materials
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat Inc. - initial API and implementation
*******************************************************************************/
package com.redhat.devtools.intellij.qute.psi.internal.extensions.roq;

import java.util.Arrays;


import com.intellij.java.library.JavaLibraryUtil;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.util.Query;
import com.redhat.devtools.intellij.qute.psi.template.datamodel.AbstractDataModelProvider;
import com.redhat.devtools.intellij.qute.psi.template.datamodel.SearchContext;
import com.redhat.qute.commons.datamodel.DataModelParameter;
import com.redhat.qute.commons.datamodel.DataModelTemplate;
import com.redhat.qute.commons.datamodel.DataModelTemplateMatcher;

/**
* Inject 'site' and 'page' as data model parameters for all Qute templates
* which belong to a Roq application.
*/
public class RoqDataModelProvider extends AbstractDataModelProvider {

@Override
public void beginSearch(SearchContext context, ProgressIndicator monitor) {
if (!RoqUtils.isRoqProject(context.getJavaProject())) {
// It is not a Roq application, don't inject site and page.
return;
}
//quarkus-roq-frontmatter

DataModelTemplate<DataModelParameter> roqTemplate = new DataModelTemplate<DataModelParameter>();
roqTemplate.setTemplateMatcher(new DataModelTemplateMatcher(Arrays.asList("**/**")));

// site
DataModelParameter site = new DataModelParameter();
site.setKey("site");
site.setSourceType(RoqJavaConstants.SITE_CLASS);
roqTemplate.addParameter(site);

// page
DataModelParameter page = new DataModelParameter();
page.setKey("page");
page.setSourceType(RoqJavaConstants.PAGE_CLASS);
roqTemplate.addParameter(page);

context.getDataModelProject().getTemplates().add(roqTemplate);
}

@Override
public void collectDataModel(Object match, SearchContext context, ProgressIndicator monitor) {
// Do nothing
}

@Override
protected String[] getPatterns() {
return null;
}

@Override
protected Query<? extends Object> createSearchPattern(SearchContext context, String pattern) {
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*******************************************************************************
* Copyright (c) 2024 Red Hat Inc. and others.
* All rights reserved. This program and the accompanying materials
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat Inc. - initial API and implementation
*******************************************************************************/
package com.redhat.devtools.intellij.qute.psi.internal.extensions.roq;

import java.util.Collection;
import java.util.List;

/**
* Roq Java constants.
*
* @author Angelo ZERR
*
*/
public class RoqJavaConstants {

private RoqJavaConstants() {
}

public static final String ROQ_ARTIFACT_ID = "quarkus-roq-frontmatter";

public static final Collection<String> ROQ_MAVEN_COORS = List.of("io.quarkiverse.roq:quarkus-roq-frontmatter");

public static final String DATA_MAPPING_ANNOTATION = "io.quarkiverse.roq.data.runtime.annotations.DataMapping";

public static final String SITE_CLASS = "io.quarkiverse.roq.frontmatter.runtime.model.Site";

public static final String PAGE_CLASS = "io.quarkiverse.roq.frontmatter.runtime.model.Page";

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*******************************************************************************
* Copyright (c) 2024 Red Hat Inc. and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
*
* Contributors:
* Red Hat Inc. - initial API and implementation
*******************************************************************************/
package com.redhat.devtools.intellij.qute.psi.internal.extensions.roq;

import java.util.List;


import com.intellij.java.library.JavaLibraryUtil;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.vfs.VirtualFile;
import com.redhat.devtools.intellij.quarkus.QuarkusModuleUtil;
import com.redhat.devtools.intellij.qute.psi.template.rootpath.ITemplateRootPathProvider;
import com.redhat.devtools.intellij.qute.psi.utils.PsiQuteProjectUtils;
import com.redhat.devtools.intellij.qute.psi.utils.PsiTypeUtils;
import com.redhat.devtools.lsp4ij.LSPIJUtils;
import com.redhat.qute.commons.TemplateRootPath;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Roq template root path provider for Roq project.
*/
public class RoqTemplateRootPathProvider implements ITemplateRootPathProvider {

private static final String ORIGIN = "roq";

private static final String[] TEMPLATES_BASE_DIRS = { "templates/", "content/", "src/main/resources/content/" };

@Override
public boolean isApplicable(Module javaProject) {
return RoqUtils.isRoqProject(javaProject);
}

@Override
public void collectTemplateRootPaths(Module javaProject, List<TemplateRootPath> rootPaths) {
VirtualFile moduleDir = QuarkusModuleUtil.getModuleDirPath(javaProject);
if (moduleDir != null) {
// templates
String templateBaseDir = LSPIJUtils.toUri(moduleDir).resolve("templates").toASCIIString();
rootPaths.add(new TemplateRootPath(templateBaseDir, ORIGIN));
// content
String contentBaseDir = LSPIJUtils.toUri(moduleDir).resolve("content").toASCIIString();
rootPaths.add(new TemplateRootPath(contentBaseDir, ORIGIN));
}
// src/main/resources/content
VirtualFile resourcesContentDir = PsiQuteProjectUtils.findBestResourcesDir(javaProject, "content");
if (resourcesContentDir != null) {
String contentBaseDir = LSPIJUtils.toUri(resourcesContentDir).resolve("content").toASCIIString();
rootPaths.add(new TemplateRootPath(contentBaseDir, ORIGIN));
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*******************************************************************************
* Copyright (c) 2024 Red Hat Inc. and others.
* All rights reserved. This program and the accompanying materials
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat Inc. - initial API and implementation
*******************************************************************************/
package com.redhat.devtools.intellij.qute.psi.internal.extensions.roq;

import com.intellij.java.library.JavaLibraryUtil;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
import org.jetbrains.annotations.NotNull;

import java.util.HashSet;
import java.util.Set;

/**
* Roq Utilities.
*/
public class RoqUtils {

/**
* Returns true if the given module is a Roq project and false otherwise.
*
* @param module the module.
* @return true if the given module is a Roq project and false otherwise.
*/
public static boolean isRoqProject(@NotNull Module module) {
if (JavaLibraryUtil.hasAnyLibraryJar(module, RoqJavaConstants.ROQ_MAVEN_COORS)) {
return true;
}

Set<Module> projectDependencies = new HashSet<>();
ModuleUtilCore.getDependencies(module, projectDependencies);
return projectDependencies
.stream()
.anyMatch(m -> RoqJavaConstants.ROQ_ARTIFACT_ID.equals(m.getName()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*******************************************************************************
* Copyright (c) 2024 Red Hat Inc. and others.
* All rights reserved. This program and the accompanying materials
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat Inc. - initial API and implementation
*******************************************************************************/
package com.redhat.devtools.intellij.qute.psi.internal.extensions.webbundler;

import java.util.Collection;
import java.util.List;

/**
* Web Bundler Java constants.
*
* @author Angelo ZERR
*
*/
public class WebBundlerJavaConstants {

private WebBundlerJavaConstants() {
}

public static final Collection<String> WEB_BUNDLER_MAVEN_COORS = List.of("io.quarkiverse.web-bundler:quarkus-roq-frontmatter");

public static final String BUNDLE_CLASS = "io.quarkiverse.web.bundler.runtime.Bundle";

}
Loading

0 comments on commit 257245e

Please sign in to comment.