diff --git a/src/main/java/plugins/tprovoost/scripteditor/scriptinghandlers/ScriptEngineHandler.java b/src/main/java/plugins/tprovoost/scripteditor/scriptinghandlers/ScriptEngineHandler.java
index a66d12531116ed55cfc7e5d29ac6501710ed3677..303fe4762ab3eafde13314147ced517ef85aba6b 100644
--- a/src/main/java/plugins/tprovoost/scripteditor/scriptinghandlers/ScriptEngineHandler.java
+++ b/src/main/java/plugins/tprovoost/scripteditor/scriptinghandlers/ScriptEngineHandler.java
@@ -9,7 +9,6 @@ import java.util.Collections;
 import java.util.HashMap;
 
 import javax.script.ScriptEngineFactory;
-import javax.script.ScriptEngineManager;
 
 import org.fife.ui.autocomplete.ParameterizedCompletion.Parameter;
 
@@ -38,8 +37,9 @@ public class ScriptEngineHandler implements PluginInstallerListener
      */
     private static final HashMap<String, ScriptEngine> engines = new HashMap<String, ScriptEngine>();
 
-    /** The factory contains all the engines. */
-    public static final ScriptEngineManager factory = new ScriptEngineManager(PluginLoader.getLoader());
+    /** The engineManager contains all the engines. */
+    public static final ScriptEngineManager engineManager = new ScriptEngineManager();
+
     private static HashMap<ScriptEngine, ScriptEngineHandler> engineHandlers = new HashMap<ScriptEngine, ScriptEngineHandler>();
     private static ScriptEngineHandler lastEngineHandler = null;
     private static ArrayList<Method> bindingFunctions;
@@ -152,9 +152,9 @@ public class ScriptEngineHandler implements PluginInstallerListener
         return engineTypesMethod;
     }
 
-    public static ScriptEngineManager getFactory()
+    public static ScriptEngineManager getEngineManager()
     {
-        return factory;
+        return engineManager;
     }
 
     private void findBindingMethodsPlugins()
@@ -280,8 +280,7 @@ public class ScriptEngineHandler implements PluginInstallerListener
             {
                 Class<?> returnType = method.getReturnType();
                 if (VariableType.isGeneric(returnType))
-                    engineFunctions.put(functionName, new VariableType(returnType,
-                            VariableType.getType(method.getGenericReturnType().toString())));
+                    engineFunctions.put(functionName, new VariableType(returnType, VariableType.getType(method.getGenericReturnType().toString())));
                 else
                     engineFunctions.put(functionName, new VariableType(returnType));
             }
diff --git a/src/main/java/plugins/tprovoost/scripteditor/scriptinghandlers/ScriptEngineManager.java b/src/main/java/plugins/tprovoost/scripteditor/scriptinghandlers/ScriptEngineManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..b36bbd63d9151a3d0922fb93e3ee9c732ac0fab7
--- /dev/null
+++ b/src/main/java/plugins/tprovoost/scripteditor/scriptinghandlers/ScriptEngineManager.java
@@ -0,0 +1,168 @@
+package plugins.tprovoost.scripteditor.scriptinghandlers;
+
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.TreeSet;
+import java.util.function.Function;
+import java.util.stream.Stream;
+
+import javax.script.ScriptEngineFactory;
+
+import icy.plugin.PluginDescriptor;
+import icy.plugin.PluginLauncher;
+import icy.plugin.PluginLoader;
+import icy.plugin.interface_.PluginScriptFactory;
+
+public class ScriptEngineManager
+{
+    private static final Comparator<ScriptEngineFactory> COMPARATOR = Comparator.comparing(ScriptEngineFactory::getEngineName,
+            Comparator.nullsLast(Comparator.naturalOrder()));
+
+    /** Set of script engine factories discovered. */
+    private final TreeSet<ScriptEngineFactory> engineSpis = new TreeSet<>(COMPARATOR);
+
+    /** Map of engine name to script engine factory. */
+    private final HashMap<String, ScriptEngineFactory> nameAssociations = new HashMap<>();
+
+    /** Map of script file extension to script engine factory. */
+    private final HashMap<String, ScriptEngineFactory> extensionAssociations = new HashMap<>();
+
+    /** Map of script MIME type to script engine factory. */
+    private final HashMap<String, ScriptEngineFactory> mimeTypeAssociations = new HashMap<>();
+
+    public ScriptEngineManager()
+    {
+        super();
+
+        for (PluginDescriptor plugin : PluginLoader.getPlugins(PluginScriptFactory.class, true, false, false))
+        {
+            try
+            {
+                // create plugin instance
+                PluginScriptFactory psf = (PluginScriptFactory) PluginLauncher.create(plugin);
+                // get the factory and add it to the list
+                engineSpis.add(psf.getScriptEngineFactory());
+            }
+            catch (Throwable t)
+            {
+                System.err.println("Error while retrieving ScriptEngineFactory from " + plugin.getName() + ":");
+                System.err.println(t.getMessage());
+            }
+        }
+    }
+
+    /**
+     * Looks up and creates a <code>ScriptEngine</code> for a given name.
+     * The algorithm first searches for a <code>ScriptEngineFactory</code> that has been
+     * registered as a handler for the specified name using the <code>registerEngineName</code>
+     * method.
+     * <br>
+     * <br>
+     * If one is not found, it searches the set of <code>ScriptEngineFactory</code> instances
+     * stored by the constructor for one with the specified name. If a <code>ScriptEngineFactory</code>
+     * is found by either method, it is used to create instance of <code>ScriptEngine</code>.
+     * 
+     * @param shortName
+     *        The short name of the <code>ScriptEngine</code> implementation.
+     *        returned by the <code>getNames</code> method of its <code>ScriptEngineFactory</code>.
+     * @return A <code>ScriptEngine</code> created by the factory located in the search. Returns null
+     *         if no such factory was found. The <code>ScriptEngineManager</code> sets its own <code>globalScope</code>
+     *         <code>Bindings</code> as the <code>GLOBAL_SCOPE</code> <code>Bindings</code> of the newly
+     *         created <code>ScriptEngine</code>.
+     * @throws NullPointerException
+     *         if shortName is null.
+     */
+    public javax.script.ScriptEngine getEngineByName(String shortName)
+    {
+        return getEngineBy(shortName, nameAssociations, ScriptEngineFactory::getNames);
+    }
+
+    /**
+     * Look up and create a <code>ScriptEngine</code> for a given extension. The algorithm
+     * used by <code>getEngineByName</code> is used except that the search starts
+     * by looking for a <code>ScriptEngineFactory</code> registered to handle the
+     * given extension using <code>registerEngineExtension</code>.
+     * 
+     * @param extension
+     *        The given extension
+     * @return The engine to handle scripts with this extension. Returns <code>null</code>
+     *         if not found.
+     * @throws NullPointerException
+     *         if extension is null.
+     */
+    public javax.script.ScriptEngine getEngineByExtension(String extension)
+    {
+        return getEngineBy(extension, extensionAssociations, ScriptEngineFactory::getExtensions);
+    }
+
+    /**
+     * Look up and create a <code>ScriptEngine</code> for a given mime type. The algorithm
+     * used by <code>getEngineByName</code> is used except that the search starts
+     * by looking for a <code>ScriptEngineFactory</code> registered to handle the
+     * given mime type using <code>registerEngineMimeType</code>.
+     * 
+     * @param mimeType
+     *        The given mime type
+     * @return The engine to handle scripts with this mime type. Returns <code>null</code>
+     *         if not found.
+     * @throws NullPointerException
+     *         if mimeType is null.
+     */
+    public javax.script.ScriptEngine getEngineByMimeType(String mimeType)
+    {
+        return getEngineBy(mimeType, mimeTypeAssociations, ScriptEngineFactory::getMimeTypes);
+    }
+
+    private javax.script.ScriptEngine getEngineBy(String selector, Map<String, ScriptEngineFactory> associations,
+            Function<ScriptEngineFactory, List<String>> valuesFn)
+    {
+        Objects.requireNonNull(selector);
+        Stream<ScriptEngineFactory> spis = Stream.concat(
+                // look for registered types first
+                Stream.ofNullable(associations.get(selector)),
+
+                engineSpis.stream().filter(spi -> {
+                    try
+                    {
+                        List<String> matches = valuesFn.apply(spi);
+                        return matches != null && matches.contains(selector);
+                    }
+                    catch (Exception exp)
+                    {
+                        debugPrint(exp);
+                        return false;
+                    }
+                }));
+        return spis.map(spi -> {
+            try
+            {
+                javax.script.ScriptEngine engine = spi.getScriptEngine();
+                return engine;
+            }
+            catch (Exception exp)
+            {
+                debugPrint(exp);
+                return null;
+            }
+        }).filter(Objects::nonNull).findFirst().orElse(null);
+    }
+
+    private static void debugPrint(Throwable exp)
+    {
+        exp.printStackTrace();
+    }
+
+    /**
+     * Returns a list whose elements are instances of all the <code>ScriptEngineFactory</code> classes
+     * found by the discovery mechanism.
+     * 
+     * @return List of all discovered <code>ScriptEngineFactory</code>s.
+     */
+    public List<ScriptEngineFactory> getEngineFactories()
+    {
+        return List.copyOf(engineSpis);
+    }
+}