Bug 575354: [Ltk-Model] Add extensible reconciler for Tex/Wikitext
with embedded content
Change-Id: I8f2ab14184be751655fe338ed70aaef4fa06184d
diff --git a/ltk/org.eclipse.statet.ltk.core/src/org/eclipse/statet/ltk/model/core/LtkModels.java b/ltk/org.eclipse.statet.ltk.core/src/org/eclipse/statet/ltk/model/core/LtkModels.java
index fb83008..ce42610 100644
--- a/ltk/org.eclipse.statet.ltk.core/src/org/eclipse/statet/ltk/model/core/LtkModels.java
+++ b/ltk/org.eclipse.statet.ltk.core/src/org/eclipse/statet/ltk/model/core/LtkModels.java
@@ -28,7 +28,7 @@
return LtkCorePlugin.getSafe().getSourceUnitManager();
}
- public static @Nullable Object getModelAdapter(final String modelTypeId, final Class<?> adapterType) {
+ public static <T> @Nullable T getModelAdapter(final String modelTypeId, final Class<T> adapterType) {
return LtkCorePlugin.getSafe().getModelAdapterFactory().get(modelTypeId, adapterType);
}
diff --git a/ltk/org.eclipse.statet.ltk.core/src/org/eclipse/statet/ltk/model/core/build/ExtensibleReconciler.java b/ltk/org.eclipse.statet.ltk.core/src/org/eclipse/statet/ltk/model/core/build/ExtensibleReconciler.java
new file mode 100644
index 0000000..413fcb9
--- /dev/null
+++ b/ltk/org.eclipse.statet.ltk.core/src/org/eclipse/statet/ltk/model/core/build/ExtensibleReconciler.java
@@ -0,0 +1,246 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2021 Stephan Wahlbrink and others.
+ #
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://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:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.ltk.model.core.build;
+
+import static org.eclipse.statet.jcommons.lang.ObjectUtils.nonNullAssert;
+
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.MultiStatus;
+
+import org.eclipse.statet.jcommons.collections.ImCollection;
+import org.eclipse.statet.jcommons.collections.ImCollections;
+import org.eclipse.statet.jcommons.collections.ImIdentitySet;
+import org.eclipse.statet.jcommons.collections.ImList;
+import org.eclipse.statet.jcommons.lang.NonNull;
+import org.eclipse.statet.jcommons.lang.NonNullByDefault;
+import org.eclipse.statet.jcommons.lang.Nullable;
+
+import org.eclipse.statet.ltk.ast.core.AstInfo;
+import org.eclipse.statet.ltk.ast.core.EmbeddingAstNode;
+import org.eclipse.statet.ltk.ast.core.util.AstPrinter;
+import org.eclipse.statet.ltk.core.SourceContent;
+import org.eclipse.statet.ltk.model.core.ModelManager;
+import org.eclipse.statet.ltk.model.core.element.SourceUnit;
+import org.eclipse.statet.ltk.model.core.element.WorkspaceSourceUnit;
+import org.eclipse.statet.ltk.project.core.LtkProject;
+
+
+@NonNullByDefault
+public abstract class ExtensibleReconciler<TProject extends LtkProject,
+ TModelContainer extends SourceUnitModelContainer<?, ?>,
+ TEmbeddedModelReconciler extends SourceUnitEmbeddedModelReconciler<?>> {
+
+
+ protected static final class ExtensionData<TConfig extends ReconcileConfig<?>,
+ TReconciler extends SourceUnitEmbeddedModelReconciler<TConfig>> {
+
+ public final String modelTypeId;
+
+ public final TReconciler reconciler;
+
+ public final TConfig config;
+
+
+ public ExtensionData(final TReconciler reconciler,
+ final TConfig config) {
+ this.modelTypeId= reconciler.getModelTypeId();
+ this.reconciler= reconciler;
+ this.config= nonNullAssert(config);
+ }
+
+
+ public static <T extends ExtensionData<?, ?>> boolean contains(final ImList<T> list, final String modelTypeId) {
+ for (final var data : list) {
+ if (data.modelTypeId == modelTypeId) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static <T extends ExtensionData<?, ?>> @Nullable T get(final ImList<T> list, final String modelTypeId) {
+ for (final var data : list) {
+ if (data.modelTypeId == modelTypeId) {
+ return data;
+ }
+ }
+ return null;
+ }
+
+ }
+
+ private static class ExtensionItem<TConfig extends ReconcileConfig<?>,
+ TReconciler extends SourceUnitEmbeddedModelReconciler<TConfig>> {
+
+ private final String modelTypeId;
+
+ private final @Nullable TReconciler reconciler;
+
+ private @Nullable ExtensionData<TConfig, TReconciler> projectData;
+
+ public ExtensionItem(final String modelTypeId, @Nullable final TReconciler reconciler) {
+ this.modelTypeId= modelTypeId;
+ this.reconciler= reconciler;
+ }
+
+
+ public void clear() {
+ this.projectData= null;
+ }
+
+ public ExtensionData<TConfig, TReconciler> init(final LtkProject project) {
+ var projectData= this.projectData;
+ if (projectData == null) {
+ projectData= createData(project.getProject(),
+ ModelManager.MODEL_DEPENDENCIES | ModelManager.RECONCILE );
+ this.projectData= projectData;
+ }
+ return projectData;
+ }
+
+ public ExtensionData<TConfig, TReconciler> createData(final @Nullable IProject project, final int level) {
+ @SuppressWarnings({ "null" })
+ final TReconciler reconciler= this.reconciler;
+ return new ExtensionData<>(reconciler, reconciler.createConfig(project, level));
+ }
+
+ }
+
+
+ protected boolean stop= false;
+
+ private final Map<String, ExtensionItem<?, TEmbeddedModelReconciler>> extensions= new HashMap<>();
+
+ private @Nullable TProject project;
+ private @Nullable MultiStatus statusCollector;
+
+ private @Nullable AstPrinter raDebugAstPrinter;
+
+
+ public ExtensibleReconciler() {
+ }
+
+
+ public void init(final TProject project, final MultiStatus statusCollector) {
+ this.project= nonNullAssert(project);
+ this.statusCollector= statusCollector;
+
+ synchronized (this.extensions) {
+ for (final var extension : this.extensions.values()) {
+ extension.clear();
+ }
+ }
+ }
+
+
+ public @Nullable MultiStatus getStatusCollector() {
+ return this.statusCollector;
+ }
+
+
+ protected abstract @Nullable TEmbeddedModelReconciler createEmbeddedModelReconciler(
+ final String modelTypeId);
+
+ protected @Nullable ExtensionItem<?, TEmbeddedModelReconciler> getExtension(final String modelTypeId) {
+ synchronized (this.extensions) {
+ var item= this.extensions.get(modelTypeId);
+ if (item== null) {
+ item= new ExtensionItem(modelTypeId, createEmbeddedModelReconciler(modelTypeId));
+ this.extensions.put(modelTypeId, item);
+ }
+ return (item.reconciler != null) ? item : null;
+ }
+ }
+
+ protected ImList<ExtensionData<?, TEmbeddedModelReconciler>> initExtensions(
+ final ImCollection<String> modelTypeIds,
+ final TModelContainer adapter, final int flags) {
+ final var items= new ArrayList<ExtensionItem<?, TEmbeddedModelReconciler>>();
+ for (final String modelTypeId : modelTypeIds) {
+ final var extension= getExtension(modelTypeId);
+ if (extension != null) {
+ items.add(extension);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ final @NonNull ExtensionData<?, TEmbeddedModelReconciler>[] dataArray= new @NonNull ExtensionData[items.size()];
+ final var project= this.project;
+ if (project != null) {
+ for (int i= 0; i < dataArray.length; i++) {
+ dataArray[i]= items.get(i).init(project);
+ }
+ }
+ else {
+ final SourceUnit sourceUnit= adapter.getSourceUnit();
+ final IProject wsProject= (sourceUnit instanceof WorkspaceSourceUnit) ?
+ ((WorkspaceSourceUnit)sourceUnit).getResource().getProject() :
+ null;
+ for (int i= 0; i < dataArray.length; i++) {
+ dataArray[i]= items.get(i).createData(wsProject, flags);
+ }
+ }
+ return ImCollections.newList(dataArray);
+ }
+
+
+ protected ImList<Object> createSourceConfig(final Object mainSourceConfig,
+ final ImList<ExtensionData<?, TEmbeddedModelReconciler>> extensions) {
+ final var configArray= new @NonNull Object[1 + extensions.size()];
+ int i= 0;
+ configArray[i++]= mainSourceConfig;
+ for (final var extensionData : extensions) {
+ configArray[i++]= extensionData.config.getSourceConfig();
+ }
+ return ImCollections.newList(configArray);
+ }
+
+ protected ImIdentitySet<String> collectEmbeddedTypeIds(final List<? extends EmbeddingAstNode> nodes) {
+ final Map<String, Boolean> ids= new IdentityHashMap<>(4);
+ for (final EmbeddingAstNode node : nodes) {
+ ids.put(node.getForeignTypeId(), Boolean.TRUE);
+ }
+ return ImCollections.toIdentitySet(ids.keySet());
+ }
+
+
+ protected void logAst(final AstInfo ast, final SourceContent content) {
+ AstPrinter printer= this.raDebugAstPrinter;
+ if (printer == null) {
+ printer= new AstPrinter(new StringWriter());
+ this.raDebugAstPrinter= printer;
+ }
+ final StringWriter out= (StringWriter)printer.getWriter();
+ out.getBuffer().setLength(0);
+ try {
+ out.append("====\n" + getClass().getSimpleName() + " AST:\n"); //$NON-NLS-1$
+ printer.print(ast.getRoot(), content.getString());
+ out.append("====\n"); //$NON-NLS-1$
+ System.out.println(out.toString());
+ }
+ catch (final Exception e) {
+ System.out.println(out.toString());
+ e.printStackTrace();
+ }
+ }
+
+}
diff --git a/ltk/org.eclipse.statet.ltk.core/src/org/eclipse/statet/ltk/model/core/build/ReconcileConfig.java b/ltk/org.eclipse.statet.ltk.core/src/org/eclipse/statet/ltk/model/core/build/ReconcileConfig.java
new file mode 100644
index 0000000..39dc96e
--- /dev/null
+++ b/ltk/org.eclipse.statet.ltk.core/src/org/eclipse/statet/ltk/model/core/build/ReconcileConfig.java
@@ -0,0 +1,37 @@
+/*=============================================================================#
+ # Copyright (c) 2021 Stephan Wahlbrink and others.
+ #
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://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:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.ltk.model.core.build;
+
+import org.eclipse.statet.jcommons.lang.NonNull;
+import org.eclipse.statet.jcommons.lang.NonNullByDefault;
+
+
+@NonNullByDefault
+public class ReconcileConfig<@NonNull TSourceConfig> {
+
+
+ private final TSourceConfig sourceConfig;
+
+
+ public ReconcileConfig(final TSourceConfig sourceConfig) {
+ this.sourceConfig= sourceConfig;
+ }
+
+
+ public TSourceConfig getSourceConfig() {
+ return this.sourceConfig;
+ }
+
+}
diff --git a/ltk/org.eclipse.statet.ltk.core/src/org/eclipse/statet/ltk/model/core/build/SourceUnitEmbeddedModelReconciler.java b/ltk/org.eclipse.statet.ltk.core/src/org/eclipse/statet/ltk/model/core/build/SourceUnitEmbeddedModelReconciler.java
new file mode 100644
index 0000000..d125ce1
--- /dev/null
+++ b/ltk/org.eclipse.statet.ltk.core/src/org/eclipse/statet/ltk/model/core/build/SourceUnitEmbeddedModelReconciler.java
@@ -0,0 +1,33 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2021 Stephan Wahlbrink and others.
+ #
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://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:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.ltk.model.core.build;
+
+import org.eclipse.core.resources.IProject;
+
+import org.eclipse.statet.jcommons.lang.NonNull;
+import org.eclipse.statet.jcommons.lang.NonNullByDefault;
+import org.eclipse.statet.jcommons.lang.Nullable;
+
+
+@NonNullByDefault
+public interface SourceUnitEmbeddedModelReconciler<TConfig extends ReconcileConfig<?>> {
+
+
+ String getModelTypeId();
+
+ @NonNull TConfig createConfig(@Nullable IProject project, int level);
+
+
+}
diff --git a/ltk/org.eclipse.statet.ltk.core/src/org/eclipse/statet/ltk/model/core/build/SourceUnitModelContainer.java b/ltk/org.eclipse.statet.ltk.core/src/org/eclipse/statet/ltk/model/core/build/SourceUnitModelContainer.java
index 1cd0c8d..f0708fa 100644
--- a/ltk/org.eclipse.statet.ltk.core/src/org/eclipse/statet/ltk/model/core/build/SourceUnitModelContainer.java
+++ b/ltk/org.eclipse.statet.ltk.core/src/org/eclipse/statet/ltk/model/core/build/SourceUnitModelContainer.java
@@ -54,10 +54,10 @@
}
- public abstract boolean isContainerFor(String modelTypeId);
-
public abstract Class<?> getAdapterClass();
+ public abstract boolean isContainerFor(String modelTypeId);
+
public @Nullable IssueTypeSet getIssueTypeSet() {
return null;
}