tm4e
tm4e copied to clipboard
Feature Request: Add ability to change theme/grammar content type associations at runtime
Hi,
My plugin used to dynamically be able to change file associations for my given editor type. Since using the TMPresentationReconciler, this ability appears to have been lost (conjecture on why later).
Here is my editor definition (NOTE : "my' is the associated file type, NOT 'pie') :

Here is the method in MySourceViewerConfiguration class:

Here is the TM4E definition (NOTE : "my' is the associated file type, NOT 'pie') :

Here is the code that I used to dynamically modify file associations to choose my editor (this previously worked before adding in the TM4E syntax highlighting) :
public void resetFileAssociations(java.util.Set<java.lang.String> extensionToAddSet) {
IWorkbench workbench = PlatformUI.getWorkbench();
final org.eclipse.ui.internal.registry.EditorRegistry editorReg = (org.eclipse.ui.internal.registry.EditorRegistry) workbench.getEditorRegistry();
org.eclipse.ui.internal.registry.EditorDescriptor editor = (org.eclipse.ui.internal.registry.EditorDescriptor) editorReg.findEditor("com.consoli.myrion.eclipse.ui.editor.MyEditorId3");
IFileEditorMapping[] originalMappings = editorReg.getFileEditorMappings();
java.util.ArrayList<org.eclipse.ui.internal.registry.FileEditorMapping> newMappings = new java.util.ArrayList<org.eclipse.ui.internal.registry.FileEditorMapping>();
boolean firstTime = false;
if (originalMappings2 == null) {
originalMappings2 = new java.util.HashSet<String>();
firstTime = true;
}
int numOriginalMappings = originalMappings.length;
for (int i = 0; i < numOriginalMappings; i++) {
org.eclipse.ui.internal.registry.FileEditorMapping m = (org.eclipse.ui.internal.registry.FileEditorMapping) originalMappings[i];
String extension = m.getExtension();
IEditorDescriptor[] editors = m.getEditors();
for (IEditorDescriptor currentEditor : editors) {
boolean isMyEditor = currentEditor == editor;
if (isMyEditor) {
if (firstTime) {
originalMappings2.add(extension);
} else {
if (!originalMappings2.contains(extension)) {
m.removeEditor(editor);
}
}
}
}
if (editors.length > 0) {
newMappings.add(m);
}
}
for (String extensionToAdd : extensionToAddSet) {
if (!originalMappings2.contains(extensionToAdd)) {
org.eclipse.ui.internal.registry.FileEditorMapping mapping = new org.eclipse.ui.internal.registry.FileEditorMapping(extensionToAdd);
System.out.println("Associating " + extensionToAdd);
mapping.addEditor(editor);
mapping.setDefaultEditor(editor);
newMappings.add(mapping);
}
}
final FileEditorMapping[] fileEditorMappings = newMappings.toArray(new org.eclipse.ui.internal.registry.FileEditorMapping[newMappings.size()]);
final Display default1 = Display.getDefault();
final Runnable runnable = new Runnable() {
@Override
public void run() {
editorReg.setFileEditorMappings(fileEditorMappings);
}
};
default1.syncExec(runnable);
}
Now we wish to dynamically associate the 'pie' file type / suffix with the same editor as 'my'.
So we call the resetFileAssociations() method with set containing ["pie", "my"]. This worked perfectly prior to tm4e integration. It also works now actually. It associates the editor type with the new suffix, but TM4E then uses the content type to grammar map and finds it empty for "pie". Same with themes.
As you would expect from the previous description, here is what happens when I attempt to access a ".pie" (previously it worked because the previous reconciler did not require configuration):

I believe that TM4E is using IGrammarRegistryManager to look up grammar / theme associations, and this cannot be modified at runtime (as far as I am aware) - therefore the .pie file suffix resolves to null. I would like to be able to alter grammar/theme associations on the fly same as is possible with the suffix to default editor associations.
The use case for this is that I have one file type that when saved, controls file associations for other file types. For example, lets say I have a file with suffix .mysettings, that file might contain a single line with a comma separated list of file suffixes such as "one, two, three". Now the builder sees when that file changes and calls the method detailed earlier. It reads the content of the file, and now dynamically associates the files with the editor (described earlier). That editor is associated with the TMPresentationReconciler. BUT, the presentation reconciler will not allow files without statically registered suffixes and themes to render. Eclipse has the functionality to change file associations at runtime, but TM4E does not (yet) (as far as I know) have the ability to render for a file suffix that has not been statically registered via the plugin.xml.
@ainsley please let me time to study your usecase.
FYI, in LSP4E, we have the registry that uses 2 strategies simultaneously:
- First is to resolve content-type -> LS association with the extensions defined in plugin.xml
- Another is to read a preference that also stores content-type -> LS associations. A preference page allows to dynamically add associations by changing the value of that preference. I believe a similar pattern could work for TM4E in Eclipse IDE.
Hello, just checking in on this. This is a blocking issue for me at the moment.
@ainsley very busy for the moment with typescript.java release, i must find time
I believe a similar pattern could work for TM4E in Eclipse IDE.
@ainsley is suggestion (manage link between grammar and content types with preferences) of @mickaelistria will work for you?
@ainsley is suggestion (manage link between grammar and content types with preferences) of @mickaelistria will work for you?
I think decoupling the grammar definition from the content type as described would work. Although there would not necessarily need to be a preferences page for my particular use case as I'd be adjusting the associations dynamically.
However I also have another use-case where I users may wish to change the associations themselves.
Maybe the associations as described in plugin.xml should be locked from modification in the preferences page, but other associations should be able to be created, edited and deleted? Maybe locking the associations should be configurable in plugin.xml itself (lock, lock_advise, open)?
And TMPresentationReconciler#setGrammar cannot help you to set grammar as you wish?
OK, so I understand that I can disable the content type to grammar type mapping by explicitly setting the grammar type for the TMPresentationReconciler within my editor configuration class (class that extends TextSourceViewerConfiguration).
I have used the following workaround logic and it seems to work:
@Override
public IPresentationReconciler getPresentationReconciler(ISourceViewer viewer) {
// Defines a TextMate Presentation reconcilier (TM4E)
final TMPresentationReconciler tmPresentationReconciler = new TMPresentationReconciler();
// WORKAROUND - START
// We are forcing the TM Presentation reconciler for this editor type to ONLY be ever of the ".my" grammar variety
{
IContentTypeManager contentTypeManager = Platform.getContentTypeManager();
IContentType myContentType = contentTypeManager.findContentTypeFor("anything" + MY_FILE_SUFFIX);
IContentType[] contentType = new IContentType[]{ myContentType};
IGrammarRegistryManager grammarRegistryManager = TMEclipseRegistryPlugin.getGrammarRegistryManager();
IGrammar tmGrammar = grammarRegistryManager.getGrammarFor(contentType);
// This should always be non-null
if (tmGrammar != null) {
tmPresentationReconciler.setGrammar(tmGrammar);
}
}
// WORKAROUND - END
return tmPresentationReconciler;
}
I think the validation code could be stronger in this case, as it assumes that there will only ever be one content type (the one associated with the TM grammar definition) in the content types registry.
But the workaround is good enough for my use case (as I have a single grammar type). It may be worth thinking through a solution where content type to TM grammar associations can be reconfigured, but I can confirm this is no longer a block for me.
@ainsley I have refactored the TMPresentationReconciler to support preferences and in this case my Document has none content type. So I'm working only with scopeName (grammar) and theme.
So now you have TMPresentationReconciler#setGrammar and TMPresentationReconciler#setThemeId which recolorizes if the grammar or theme changed. You don't need in this case content type. Content type is helpful if you don't set grammar.
See https://github.com/eclipse/tm4e/blob/master/org.eclipse.tm4e.ui/src/main/java/org/eclipse/tm4e/ui/internal/preferences/TMViewer.java that I'm using for preview inside preferences:

If it works for you, please close this issue. Thanks!
With the current version of TM4E, I cannot set a content-type for a grammar added manually. I've added a grammar ( graphQL.tmLanguage ) and I would like to associate it with a local content-type. I do not see how I can do it from UI.
I've added a grammar ( graphQL.tmLanguage ) and I would like to associate it with a local content-type. I do not see how I can do it from UI.
It's not possible today to use content type, you must use file extension. I had done this choice because with Oxygen/Neon you was not able to create custom content type, that's why I have supported file extension.
It seems @mickaelistria that you are working on create custom content type. In this case I think it could be interested to do that.
It's not possible today to use content type, you must use file extension. I had done this choice because with Oxygen/Neon you was not able to create custom content type, that's why I have supported file extension.
That didn't work for my use-case. Opening a .graphql file with generic editor and graphql grammar available doesn't highlight the code.
It seems @mickaelistria that you are working on create custom content type. In this case I think it could be interested to do that.
This has been available since Oxygen M4 ( https://bugs.eclipse.org/bugs/show_bug.cgi?id=98230 ).
That didn't work for my use-case. Opening a .graphql file with generic editor and graphql grammar available doesn't highlight the code.
It's because you cannot use Generic Editor, you must use the TextMate Editor for the moment. We must implement https://github.com/eclipse/tm4e/issues/17 I have tried to do that quicly but I must fix problem when grammar is not found (in the case of generic editor, you must not see errors)
Issue #17 would become less important once this one is fixed. In the Eclipse IDE, dealing with content-type scales better and is less error prone.
To fix this issue #17 , you must add add in the org.eclipse.tm4e.ui/plugin.xml
<extension
point="org.eclipse.ui.genericeditor.presentationReconcilers">
<presentationReconciler
class="org.eclipse.tm4e.ui.text.TMPresentationReconciler"
contentType="org.eclipse.core.runtime.text">
</presentationReconciler>
</extension>
To use TMPresentationReconciler with Generic Editor.
It should work with your use case, no?
Issue #17 would become less important
I don't understand? You mean that you can manage org.eclipse.ui.genericeditor.presentationReconcilers with Java API?
You're right, it would still require ability to map dynamically a presentationReconciler to a content-type.