Skip to content
Draft
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
1 change: 1 addition & 0 deletions org.eclipse.tm4e.ui/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Export-Package: org.eclipse.tm4e.ui,
org.eclipse.tm4e.ui.internal.widgets;x-friends:="org.eclipse.tm4e.languageconfiguration",
org.eclipse.tm4e.ui.model,
org.eclipse.tm4e.ui.samples,
org.eclipse.tm4e.ui.templates,
org.eclipse.tm4e.ui.text,
org.eclipse.tm4e.ui.themes,
org.eclipse.tm4e.ui.themes.css
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions org.eclipse.tm4e.ui/plugin.properties
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ TextMatePreferencePage.name=TextMate
GrammarPreferencePage.name=Grammar
TaskTagsPreferencePage.name=Task Tags
ThemePreferencePage.name=Theme
TemplatesPreferencePage.name=Templates

# Wizards
TextMateWizard.category=TextMate
Expand Down
40 changes: 40 additions & 0 deletions org.eclipse.tm4e.ui/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@
class="org.eclipse.tm4e.ui.internal.preferences.ThemePreferencePage"
id="org.eclipse.tm4e.ui.preferences.ThemePreferencePage"
category="org.eclipse.tm4e.ui.preferences.TextMatePreferencePage" />
<page name="%TemplatesPreferencePage.name"
class="org.eclipse.tm4e.ui.internal.preferences.CustomCodeTemplatePreferencePage"
id="org.eclipse.tm4e.ui.preferences.CustomCodeTemplatePreferencePage"
category="org.eclipse.tm4e.ui.preferences.TextMatePreferencePage">
</page>
</extension>

<!-- Wizards -->
Expand Down Expand Up @@ -155,4 +160,39 @@
class="org.eclipse.tm4e.ui.internal.hover.TMTokenTextHover"
contentType="org.eclipse.core.runtime.text" />
</extension>

<extension point="org.eclipse.ui.editors.templates">
<contextType
class="org.eclipse.tm4e.ui.templates.DefaultTMTemplateContextType"
id="org.eclipse.tm4e.ui.templates.context"
name="Default context"
registryId="org.eclipse.tm4e.ui.templates">
</contextType>
<contextType
class="org.eclipse.tm4e.ui.templates.CommentTemplateContextType"
id="org.eclipse.tm4e.ui.templates.context.comment"
name="Comment"
registryId="org.eclipse.tm4e.ui.templates">
</contextType>
<contextType
class="org.eclipse.tm4e.ui.templates.DocumentationCommentTemplateContextType"
id="org.eclipse.tm4e.ui.templates.context.comment.doc"
name="Documentation Comment"
registryId="org.eclipse.tm4e.ui.templates">
</contextType>
<include
file="src/main/resources/templates/templates.xml"
translations="src/main/resources/templates/templates.properties">
</include>
<contextTypeRegistry
id="org.eclipse.tm4e.ui.templates">
</contextTypeRegistry>
</extension>

<extension point="org.eclipse.ui.genericeditor.contentAssistProcessors">
<contentAssistProcessor
class="org.eclipse.tm4e.ui.internal.templates.TMTemplateCompletionProcessor"
contentType="org.eclipse.core.runtime.text" />
</extension>

</plugin>
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*******************************************************************************
* Copyright (c) 2026 Advantest Europe GmbH 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/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Dietrich Travkin (SOLUNAR GmbH) - initial implementation
*******************************************************************************/
package org.eclipse.tm4e.ui;

import java.net.URL;

import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.ImageRegistry;
import org.eclipse.swt.graphics.Image;
import org.osgi.framework.Bundle;

public final class TMImages {

private static final String ICONS_PATH = "$nl$/icons/full/"; //$NON-NLS-1$
private static final String OBJECT = ICONS_PATH + "obj16/"; // basic colors - size 16x16 //$NON-NLS-1$

public static final String IMG_TEMPLATE = "IMG_TEMPALTE"; //$NON-NLS-1$

private TMImages() {
// no instantiation desired
}

private static @Nullable ImageRegistry imageRegistry;

public static void initalize(final ImageRegistry registry) {
imageRegistry = registry;

registerImage(IMG_TEMPLATE, OBJECT + "template_obj.svg"); //$NON-NLS-1$
}

private static void registerImage(final String key, final String path) {
ImageDescriptor desc = ImageDescriptor.getMissingImageDescriptor();
final Bundle bundle = Platform.getBundle(TMUIPlugin.PLUGIN_ID);
final ImageRegistry imageRegistry = getImageRegistry();
URL url = null;
if (bundle != null) {
url = FileLocator.find(bundle, new Path(path), null);
if (url != null) {
desc = ImageDescriptor.createFromURL(url);
}
}
if (imageRegistry != null) {
imageRegistry.put(key, desc);
}
}

/**
* Returns the {@link Image} identified by the given key, or <code>null</code> if it does not exist.
*/
public static @Nullable Image getImage(final String key) {
final ImageRegistry imageRegistry = getImageRegistry();
if (imageRegistry == null) {
return null;
}
return imageRegistry.get(key);
}

/**
* Returns the {@link ImageDescriptor} identified by the given key, or <code>null</code> if it does not exist.
*/
public static @Nullable ImageDescriptor getImageDescriptor(final String key) {
final ImageRegistry imageRegistry = getImageRegistry();
if (imageRegistry == null) {
return null;
}
return imageRegistry.getDescriptor(key);
}

public static @Nullable ImageRegistry getImageRegistry() {
if (imageRegistry == null) {
final TMUIPlugin plugin = TMUIPlugin.getDefault();
if (plugin == null) {
return null;
}
imageRegistry = plugin.getImageRegistry();
}
return imageRegistry;
}

}
123 changes: 123 additions & 0 deletions org.eclipse.tm4e.ui/src/main/java/org/eclipse/tm4e/ui/TMUIPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@
*
* Contributors:
* Angelo Zerr <[email protected]> - initial API and implementation
* Dietrich Travkin (SOLUNAR GmbH) - Additions for custom code templates
*/
package org.eclipse.tm4e.ui;

import java.io.IOException;
import java.util.Iterator;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
Expand All @@ -19,14 +22,29 @@
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jface.text.templates.TemplateContextType;
import org.eclipse.jface.text.templates.persistence.TemplateStore;
import org.eclipse.text.templates.ContextTypeRegistry;
import org.eclipse.tm4e.core.grammar.IGrammar;
import org.eclipse.tm4e.core.internal.utils.NullSafetyHelper;
import org.eclipse.tm4e.registry.IGrammarDefinition;
import org.eclipse.tm4e.registry.ITMScope;
import org.eclipse.tm4e.registry.TMEclipseRegistryPlugin;
import org.eclipse.tm4e.ui.internal.model.TMModelManager;
import org.eclipse.tm4e.ui.internal.samples.SampleManager;
import org.eclipse.tm4e.ui.internal.themes.ThemeManager;
import org.eclipse.tm4e.ui.model.ITMModelManager;
import org.eclipse.tm4e.ui.samples.ISampleManager;
import org.eclipse.tm4e.ui.templates.CommentTemplateContextType;
import org.eclipse.tm4e.ui.templates.DefaultTMTemplateContextType;
import org.eclipse.tm4e.ui.templates.DocumentationCommentTemplateContextType;
import org.eclipse.tm4e.ui.templates.TMLanguageTemplateContextType;
import org.eclipse.tm4e.ui.themes.ColorManager;
import org.eclipse.tm4e.ui.themes.IThemeManager;
import org.eclipse.ui.editors.text.templates.ContributionContextTypeRegistry;
import org.eclipse.ui.editors.text.templates.ContributionTemplateStore;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;

Expand All @@ -39,9 +57,17 @@ public class TMUIPlugin extends AbstractUIPlugin {
public static final String PLUGIN_ID = "org.eclipse.tm4e.ui"; //$NON-NLS-1$
private static final String TRACE_ID = PLUGIN_ID + "/trace"; //$NON-NLS-1$

// IDs for custom code templates
private static final String CUSTOM_TEMPLATES_KEY = PLUGIN_ID + ".text.templates.custom"; //$NON-NLS-1$
private static final String TEMPLATES_REGISTRY_ID = PLUGIN_ID + ".templates"; //$NON-NLS-1$

// The shared instance
private static volatile @Nullable TMUIPlugin plugin;

// registry and store for custom code templates
private @Nullable ContributionContextTypeRegistry contextTypeRegistry = null;
private @Nullable TemplateStore templateStore = null;

/**
* Returns the shared instance
*
Expand Down Expand Up @@ -146,12 +172,109 @@ public void close() throws SecurityException {
}
});
}

TMImages.initalize(getImageRegistry());
}

@Override
public void stop(final BundleContext context) throws Exception {
if (templateStore != null) {
templateStore.stopListeningForPreferenceChanges();
}
ColorManager.getInstance().dispose();
plugin = null;
super.stop(context);
}

public ContextTypeRegistry getTemplateContextRegistry() {
@NonNull
ContributionContextTypeRegistry result;

if (contextTypeRegistry == null) {
result = new ContributionContextTypeRegistry(TEMPLATES_REGISTRY_ID);
contextTypeRegistry = result;

result.addContextType(DefaultTMTemplateContextType.CONTEXT_ID);
result.addContextType(CommentTemplateContextType.CONTEXT_ID);
result.addContextType(DocumentationCommentTemplateContextType.CONTEXT_ID);

// Add language-specific context types
// TODO Skip certain grammars? Some grammars have no name or are only used for highlighting code snippets, e.g. in Markdown
final IGrammarDefinition[] grammarDefinitions = TMEclipseRegistryPlugin.getGrammarRegistryManager().getDefinitions();
for (final IGrammarDefinition definition : grammarDefinitions) {
final ITMScope languageScope = definition.getScope();
final IGrammar languageGrammar = TMEclipseRegistryPlugin.getGrammarRegistryManager().getGrammarForScope(languageScope);
if (languageGrammar != null) {
String name = languageGrammar.getName();
if (name == null) {
name = "";
}
name += " (" + languageScope.getName() + ")";
final TMLanguageTemplateContextType languageContextType = new TMLanguageTemplateContextType(
name, languageScope);
result.addContextType(languageContextType);
}
}

} else {
result = NullSafetyHelper.castNonNull(contextTypeRegistry);
}
return result;
}

@SuppressWarnings("deprecation")
private static class ContextTypeRegistryWrapper extends org.eclipse.jface.text.templates.ContextTypeRegistry {

private final ContextTypeRegistry delegate;

public ContextTypeRegistryWrapper(final ContextTypeRegistry registry) {
this.delegate = registry;
}

// TODO How can this null-safety check be handled correctly?
@SuppressWarnings("null")
@Override
public Iterator<@Nullable TemplateContextType> contextTypes() {
return delegate.contextTypes();
}

@Override
public void addContextType(final @Nullable TemplateContextType contextType) {
delegate.addContextType(contextType);
}

@Override
public @Nullable TemplateContextType getContextType(final @Nullable String id) {
return delegate.getContextType(id);
}

}

public static ContextTypeRegistryWrapper from(final ContextTypeRegistry registry) {
return new ContextTypeRegistryWrapper(registry);
}

public TemplateStore getTemplateStore() {
@NonNull
TemplateStore result;

if (templateStore == null) {
result = new ContributionTemplateStore(from(getTemplateContextRegistry()), getPreferenceStore(),
CUSTOM_TEMPLATES_KEY);
templateStore = result;

try {
result.load();
} catch (final IOException e) {
Platform.getLog(this.getClass()).error(e.getMessage(), e);
}

result.startListeningForPreferenceChanges();
} else {
result = NullSafetyHelper.castNonNull(templateStore);
}

return result;
}

}
Loading