A plugin to show desugared and decompiled code produced by javac.

diff --git a/extra/java.debugjavac/.gitignore b/extra/java.debugjavac/.gitignore
new file mode 100644
index 0000000..a6f89c2
--- /dev/null
+++ b/extra/java.debugjavac/.gitignore
@@ -0,0 +1 @@
+/target/
\ No newline at end of file
diff --git a/extra/java.debugjavac/pom.xml b/extra/java.debugjavac/pom.xml
new file mode 100644
index 0000000..4a31783
--- /dev/null
+++ b/extra/java.debugjavac/pom.xml
@@ -0,0 +1,217 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>org.netbeans.modules</groupId>
+    <artifactId>java.debugjavac</artifactId>
+    <version>1.0</version>
+    <packaging>nbm</packaging>
+    <name>Show javac output</name>
+
+    <parent>
+        <groupId>org.apache.netbeans</groupId>
+        <artifactId>netbeans-parent</artifactId>
+        <version>2</version>
+    </parent>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.netbeans.utilities</groupId>
+                <artifactId>nbm-maven-plugin</artifactId>
+                <version>4.3</version>
+                <extensions>true</extensions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.8.1</version>
+                <configuration>
+                    <source>1.8</source>
+                    <target>1.8</target>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <version>3.1.2</version>
+                <configuration>
+                    <archive>
+                        <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+                    </archive>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-source-plugin</artifactId>
+                <version>2.1.2</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>jar-no-fork</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.rat</groupId>
+                <artifactId>apache-rat-plugin</artifactId>
+                <configuration>
+                    <excludes>
+                        <exclude>src/main/nbm/manifest.mf</exclude>
+                    </excludes>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+    <dependencies>
+        <dependency>
+            <groupId>org.netbeans.api</groupId>
+            <artifactId>org-netbeans-api-annotations-common</artifactId>
+            <version>${netbeans.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.netbeans.api</groupId>
+            <artifactId>org-openide-awt</artifactId>
+            <version>${netbeans.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.netbeans.api</groupId>
+            <artifactId>org-openide-nodes</artifactId>
+            <version>${netbeans.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.netbeans.api</groupId>
+            <artifactId>org-openide-text</artifactId>
+            <version>${netbeans.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.netbeans.api</groupId>
+            <artifactId>org-openide-util</artifactId>
+            <version>${netbeans.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.netbeans.api</groupId>
+            <artifactId>org-openide-util-lookup</artifactId>
+            <version>${netbeans.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.netbeans.api</groupId>
+            <artifactId>org-openide-filesystems</artifactId>
+            <version>${netbeans.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.netbeans.api</groupId>
+            <artifactId>org-openide-modules</artifactId>
+            <version>${netbeans.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.netbeans.api</groupId>
+            <artifactId>org-openide-windows</artifactId>
+            <version>${netbeans.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.netbeans.api</groupId>
+            <artifactId>org-netbeans-api-java</artifactId>
+            <version>${netbeans.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.netbeans.api</groupId>
+            <artifactId>org-netbeans-api-java-classpath</artifactId>
+            <version>${netbeans.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.netbeans.api</groupId>
+            <artifactId>org-netbeans-modules-java-platform</artifactId>
+            <version>${netbeans.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.netbeans.api</groupId>
+            <artifactId>org-openide-loaders</artifactId>
+            <version>${netbeans.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.netbeans.api</groupId>
+            <artifactId>org-netbeans-modules-lexer</artifactId>
+            <version>${netbeans.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.netbeans.api</groupId>
+            <artifactId>org-netbeans-modules-editor-lib</artifactId>
+            <version>${netbeans.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.netbeans.api</groupId>
+            <artifactId>org-netbeans-modules-editor-lib2</artifactId>
+            <version>${netbeans.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.netbeans.api</groupId>
+            <artifactId>org-netbeans-modules-editor</artifactId>
+            <version>${netbeans.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.netbeans.api</groupId>
+            <artifactId>org-netbeans-modules-editor-errorstripe-api</artifactId>
+            <version>${netbeans.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.netbeans.api</groupId>
+            <artifactId>org-netbeans-modules-parsing-api</artifactId>
+            <version>${netbeans.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.netbeans.api</groupId>
+            <artifactId>org-netbeans-core-multiview</artifactId>
+            <version>${netbeans.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.netbeans.api</groupId>
+            <artifactId>org-netbeans-modules-java-source-base</artifactId>
+            <version>${netbeans.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.netbeans.api</groupId>
+            <artifactId>org-netbeans-modules-java-source</artifactId>
+            <version>${netbeans.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.netbeans.api</groupId>
+            <artifactId>org-netbeans-modules-nbjunit</artifactId>
+            <version>${netbeans.version}</version>
+            <scope>test</scope>
+        </dependency>
+<!--        <dependency>
+            <groupId>com.sun</groupId>
+            <artifactId>tools-jar</artifactId>
+            <version>8</version>
+            <systemPath>${java.home}/../lib/tools.jar</systemPath>
+            <scope>system</scope>
+        </dependency>-->
+    </dependencies>
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <netbeans.version>RELEASE112</netbeans.version>
+    </properties>
+</project>
\ No newline at end of file
diff --git a/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/Bundle.properties b/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/Bundle.properties
new file mode 100644
index 0000000..92d3045
--- /dev/null
+++ b/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/Bundle.properties
@@ -0,0 +1,26 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+OpenIDE-Module-Display-Category=Java
+OpenIDE-Module-Long-Description=\
+    Find out how javac desugars and compiles Java source code
+OpenIDE-Module-Name=Debugging for javac
+CTL_DecompiledTabCaption=Decompiled
+DecompileToolbar.jLabel1.text=Compiler:
+DecompileToolbar.jLabel2.text=Decompiler:
+OpenIDE-Module-Short-Description=Find out how javac desugars and compiles Java source code
+DecompileToolbar.jLabel3.text=Extra javac options:
diff --git a/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/CompilerDescription.java b/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/CompilerDescription.java
new file mode 100644
index 0000000..0353d10
--- /dev/null
+++ b/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/CompilerDescription.java
@@ -0,0 +1,229 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.debugjavac;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.beans.XMLDecoder;
+import java.beans.XMLEncoder;
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+import org.netbeans.api.java.platform.JavaPlatform;
+import org.netbeans.api.java.platform.JavaPlatformManager;
+import org.netbeans.api.java.platform.Specification;
+import org.netbeans.modules.java.debugjavac.Decompiler.Input;
+import org.netbeans.modules.java.debugjavac.Decompiler.Result;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileUtil;
+import org.openide.modules.InstalledFileLocator;
+import org.openide.modules.SpecificationVersion;
+import org.openide.util.Exceptions;
+
+/**
+ *
+ * @author lahvac
+ */
+public interface CompilerDescription {
+    public String getName();
+    public boolean isValid();
+    public Result decompile(DecompilerDescription decompiler, Input input);
+
+    public static class Factory {
+        private static Collection<? extends CompilerDescription> descriptions;
+        public static synchronized Collection<? extends CompilerDescription> descriptions() {
+            if (descriptions != null) return descriptions;
+
+            File moduleJar = InstalledFileLocator.getDefault().locate("modules/org-netbeans-modules-java-debugjavac.jar", null, false);
+
+            List<CompilerDescription> result = new ArrayList<>();
+
+            for (JavaPlatform platform : JavaPlatformManager.getDefault().getInstalledPlatforms()) {
+                if (!"j2se".equals(platform.getSpecification().getName())) continue;
+
+                for (FileObject installDir : platform.getInstallFolders()) {
+                    FileObject toolsJar = installDir.getFileObject("lib/tools.jar");
+                    FileObject jrtfs = installDir.getFileObject("lib/jrt-fs.jar");
+
+                    if (toolsJar != null || jrtfs != null) {
+                        result.add(new ExecCompilerDescription(platform, moduleJar, toolsJar != null ? FileUtil.toFile(toolsJar) : null));
+                    }
+                }
+            }
+
+            return descriptions = Collections.unmodifiableList(result);
+        }
+
+        static {
+            JavaPlatformManager.getDefault().addPropertyChangeListener(new PropertyChangeListener() {
+                @Override public void propertyChange(PropertyChangeEvent evt) {
+                    synchronized (CompilerDescription.class) {
+                        descriptions = null;
+                        //TODO: should refresh the existing combos
+                    }
+                }
+            });
+        }
+        
+        private static class LoaderBased implements CompilerDescription {
+            public final String displayName;
+            public final URL[] jars;
+
+            private LoaderBased(String displayName, URL[] jars) {
+                this.displayName = displayName;
+                this.jars = jars;
+            }
+
+            @Override
+            public String getName() {
+                return displayName;
+            }
+
+            private final AtomicReference<Boolean> valid = new AtomicReference<>();
+
+            public boolean isValid() {
+                Boolean val = valid.get();
+
+                if (val == null) {
+                    valid.set(val = isValidImpl());
+                }
+
+                return val;
+            }
+
+            private boolean isValidImpl() {
+                ClassLoader loader = getClassLoader();
+
+                if (loader == null) return false;
+
+                try {
+                    Class.forName("javax.tools.ToolProvider", true, loader);
+                    return true;
+                } catch (Throwable ex) {
+                    return false;
+                }
+            }
+
+            private ClassLoader classLoader;
+
+            private synchronized  ClassLoader getClassLoader() {
+                if (classLoader == null) {
+                    try {
+                        List<URL> urls = new ArrayList<>();
+
+                        urls.addAll(Arrays.asList(jars));
+                        urls.add(InstalledFileLocator.getDefault().locate("modules/ext/decompile.jar", null, false).toURI().toURL());
+
+                        classLoader = new URLClassLoader(urls.toArray(new URL[0]), DecompiledTab.class.getClassLoader());
+                    } catch (MalformedURLException ex) {
+                        Exceptions.printStackTrace(ex);
+                    }
+                }
+
+                return classLoader;
+            }
+
+            @Override
+            public Result decompile(DecompilerDescription decompiler, Input input) {
+                ClassLoader loader = getClassLoader();
+
+                if (loader == null) return new Result("Internal error - cannot find ClassLoader.", null, null);
+
+                return decompiler.createDecompiler(loader).decompile(input);
+            }
+
+        }
+
+        private static final class ExecCompilerDescription implements CompilerDescription {
+
+            private static final SpecificationVersion HAS_ADD_EXPORTS = new SpecificationVersion("9");
+
+            private final JavaPlatform platform;
+            private final File moduleJar;
+            private final File toolsJar;
+
+            public ExecCompilerDescription(JavaPlatform platform, File moduleJar, File toolsJar) {
+                this.platform = platform;
+                this.moduleJar = moduleJar;
+                this.toolsJar = toolsJar;
+            }
+
+            @Override
+            public String getName() {
+                return platform.getDisplayName();
+            }
+
+            @Override
+            public boolean isValid() {
+                return true; //TODO
+            }
+
+            @Override
+            public Result decompile(DecompilerDescription decompiler, Input input) {
+                try {
+                    List<String> args = new ArrayList<>();
+                    args.add(FileUtil.toFile(platform.findTool("java")).getAbsolutePath());
+                    if (toolsJar != null) {
+                        args.add("-Xbootclasspath/p:" + toolsJar.getAbsolutePath());
+                    }
+                    if (platform.getSpecification().getVersion().compareTo(HAS_ADD_EXPORTS) >= 0) {
+                        args.add("--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED");
+                        args.add("--add-exports=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED");
+                        args.add("--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED");
+                        args.add("--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED");
+                        args.add("--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED");
+                        args.add("--add-exports=jdk.jdeps/com.sun.tools.classfile=ALL-UNNAMED");
+                        args.add("--add-exports=jdk.jdeps/com.sun.tools.javap=ALL-UNNAMED");
+                    }
+                    args.add("-classpath");
+                    args.add(moduleJar.getAbsolutePath());
+                    args.add("org.netbeans.modules.java.debugjavac.impl.Main");
+                    args.add(decompiler.id);
+                    Process process = Runtime.getRuntime().exec(args.toArray(new String[0]));
+                    try (XMLEncoder enc = new XMLEncoder(process.getOutputStream())) {
+                        enc.writeObject(input);
+                    }
+                    try (XMLDecoder decl = new XMLDecoder(process.getInputStream())) {
+                        return (Result) decl.readObject();
+                    }
+                } catch (IOException ex) {
+                    StringWriter exception = new StringWriter();
+                    try (PrintWriter exceptionPW = new PrintWriter(exception)) {
+                        ex.printStackTrace(exceptionPW);
+                    }
+                    return new Result(exception.toString(), null, null);
+                }
+                
+            }
+
+        }
+
+    }
+
+}
diff --git a/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/DJavaDataObject.java b/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/DJavaDataObject.java
new file mode 100644
index 0000000..8d89340
--- /dev/null
+++ b/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/DJavaDataObject.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.debugjavac;
+
+import java.io.IOException;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.MIMEResolver;
+import org.openide.loaders.DataObject;
+import org.openide.loaders.DataObjectExistsException;
+import org.openide.loaders.MultiDataObject;
+import org.openide.loaders.MultiFileLoader;
+import org.openide.util.NbBundle.Messages;
+
+@Messages({
+    "LBL_DJava_LOADER=Files of DJava"
+})
+@MIMEResolver.ExtensionRegistration(
+        displayName = "#LBL_DJava_LOADER",
+        mimeType = "text/x-java-decompiled",
+        extension = {"djava"},
+        position = 999207
+        )
+@DataObject.Registration(
+        mimeType = "text/x-java-decompiled",
+//        iconBase = "SET/PATH/TO/ICON/HERE",
+        displayName = "#LBL_DJava_LOADER",
+        position = 300
+        )
+public class DJavaDataObject extends MultiDataObject {
+
+    public DJavaDataObject(FileObject pf, MultiFileLoader loader) throws DataObjectExistsException, IOException {
+        super(pf, loader);
+        registerEditor("text/x-java-decompiled", false);
+    }
+
+    @Override
+    protected int associateLookup() {
+        return 1;
+    }
+
+}
diff --git a/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/DecompileToolbar.form b/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/DecompileToolbar.form
new file mode 100644
index 0000000..14a9135
--- /dev/null
+++ b/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/DecompileToolbar.form
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+
+<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="0" attributes="0">
+              <Component id="jLabel1" min="-2" max="-2" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="compiler" min="-2" max="-2" attributes="0"/>
+              <EmptySpace type="unrelated" max="-2" attributes="0"/>
+              <Component id="jLabel2" min="-2" max="-2" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="decompiler" min="-2" max="-2" attributes="0"/>
+              <EmptySpace type="unrelated" max="-2" attributes="0"/>
+              <Component id="jLabel3" min="-2" max="-2" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="extraOptions" pref="338" max="32767" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="103" groupAlignment="3" attributes="0">
+              <Component id="jLabel1" alignment="3" min="-2" max="-2" attributes="0"/>
+              <Component id="compiler" alignment="3" min="-2" max="-2" attributes="0"/>
+              <Component id="jLabel2" alignment="3" min="-2" max="-2" attributes="0"/>
+              <Component id="decompiler" alignment="3" min="-2" max="-2" attributes="0"/>
+              <Component id="jLabel3" alignment="3" min="-2" max="-2" attributes="0"/>
+              <Component id="extraOptions" alignment="3" min="-2" max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Component class="javax.swing.JLabel" name="jLabel1">
+      <Properties>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="org/netbeans/modules/java/debugjavac/Bundle.properties" key="DecompileToolbar.jLabel1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JComboBox" name="compiler">
+      <Properties>
+        <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
+          <StringArray count="4">
+            <StringItem index="0" value="Item 1"/>
+            <StringItem index="1" value="Item 2"/>
+            <StringItem index="2" value="Item 3"/>
+            <StringItem index="3" value="Item 4"/>
+          </StringArray>
+        </Property>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JLabel" name="jLabel2">
+      <Properties>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="org/netbeans/modules/java/debugjavac/Bundle.properties" key="DecompileToolbar.jLabel2.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JComboBox" name="decompiler">
+      <Properties>
+        <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
+          <StringArray count="4">
+            <StringItem index="0" value="Item 1"/>
+            <StringItem index="1" value="Item 2"/>
+            <StringItem index="2" value="Item 3"/>
+            <StringItem index="3" value="Item 4"/>
+          </StringArray>
+        </Property>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JLabel" name="jLabel3">
+      <Properties>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="org/netbeans/modules/java/debugjavac/Bundle.properties" key="DecompileToolbar.jLabel3.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JComboBox" name="extraOptions">
+      <Properties>
+        <Property name="editable" type="boolean" value="true"/>
+        <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
+          <StringArray count="0"/>
+        </Property>
+      </Properties>
+    </Component>
+  </SubComponents>
+</Form>
diff --git a/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/DecompileToolbar.java b/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/DecompileToolbar.java
new file mode 100644
index 0000000..3b29341
--- /dev/null
+++ b/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/DecompileToolbar.java
@@ -0,0 +1,334 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.debugjavac;
+
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.prefs.BackingStoreException;
+import java.util.prefs.Preferences;
+import javax.swing.ComboBoxModel;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.JList;
+import javax.swing.MutableComboBoxModel;
+import javax.swing.event.ListDataEvent;
+import javax.swing.event.ListDataListener;
+import org.openide.filesystems.FileObject;
+import org.openide.util.Exceptions;
+import org.openide.util.NbPreferences;
+import org.openide.util.WeakListeners;
+
+/**
+ *
+ * @author lahvac
+ */
+public class DecompileToolbar extends javax.swing.JPanel {
+
+    private static final int HISTORY_LIMIT = 2;
+    
+    public DecompileToolbar(final FileObject decompiled, final FileObject originalSource) {
+        initComponents();
+        
+        DefaultComboBoxModel<CompilerDescription> compilerModel = new DefaultComboBoxModel<>();
+        Collection<? extends CompilerDescription> compilerDescriptions = CompilerDescription.Factory.descriptions();
+        
+        for (CompilerDescription cd : compilerDescriptions) {
+            compilerModel.addElement(cd);
+        }
+        
+        compiler.setModel(compilerModel);
+        compiler.setRenderer(new DefaultListCellRenderer() {
+            @Override public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+                if (value instanceof CompilerDescription) {
+                    CompilerDescription compilerDescription = (CompilerDescription) value;
+                    
+                    value = compilerDescription.getName() + (compilerDescription.isValid() ? "" : " - unusable");
+                }
+                return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
+            }
+        });
+        compiler.addActionListener(new ActionListener() {
+            @Override public void actionPerformed(ActionEvent e) {
+                try {
+                    decompiled.setAttribute(CompilerDescription.class.getName(), compiler.getSelectedItem());
+                } catch (IOException ex) {
+                    Exceptions.printStackTrace(ex);
+                }
+            }
+        });
+        
+        DefaultComboBoxModel<DecompilerDescription> decompilerModel = new DefaultComboBoxModel<>();
+        List<DecompilerDescription> decompilers = new ArrayList<>();
+        
+        if (compilerDescriptions.size() > 0) {
+            compiler.setSelectedIndex(0);
+            
+            for (DecompilerDescription decompiler : DecompilerDescription.getDecompilers()) {
+                decompilerModel.addElement(decompiler);
+                decompilers.add(decompiler);
+            }
+        }
+        
+        decompiler.setModel(decompilerModel);
+        decompiler.setRenderer(new DefaultListCellRenderer() {
+            @Override public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+                if (value instanceof DecompilerDescription) value = ((DecompilerDescription) value).displayName;
+                return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
+            }
+        });
+        decompiler.addActionListener(new ActionListener() {
+            @Override public void actionPerformed(ActionEvent e) {
+                try {
+                    decompiled.setAttribute(DecompilerDescription.class.getName(), ((DecompilerDescription) decompiler.getSelectedItem()).id);
+                } catch (IOException ex) {
+                    Exceptions.printStackTrace(ex);
+                }
+            }
+        });
+        decompiler.setSelectedIndex(0);
+        extraOptions.setModel(createModel());
+        Object extraParams = originalSource.getAttribute(DecompiledTab.PROP_EXTRA_PARAMS);
+        if (extraParams instanceof String) {
+            try {
+                extraOptions.setSelectedItem(extraParams);
+                decompiled.setAttribute(DecompiledTab.PROP_EXTRA_PARAMS, extraParams);
+            } catch (IOException ex) {
+                Exceptions.printStackTrace(ex);
+            }
+        }
+        extraOptions.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                try {
+                    String selected = (String) extraOptions.getSelectedItem();
+
+                    masterModel.removeElement(selected);
+                    masterModel.insertElementAt(selected, 0);
+
+                    while (masterModel.getSize() > HISTORY_LIMIT) {
+                        masterModel.removeElementAt(masterModel.getSize() - 1);
+                    }
+
+                    storeMasterData();
+
+                    extraOptions.getModel().setSelectedItem(selected); //the above changes the selection
+
+                    decompiled.setAttribute(DecompiledTab.PROP_EXTRA_PARAMS, selected);
+                    originalSource.setAttribute(DecompiledTab.PROP_EXTRA_PARAMS, selected);
+
+                } catch (IOException ex) {
+                    Exceptions.printStackTrace(ex);
+                }
+            }
+        });
+    }
+
+    private static MutableComboBoxModel<String> masterModel;
+
+    private static final String KEY_EXTRA_PARAMS_HISTORY = "extraParamsHistory";
+
+    private static Preferences getHistoryNode() {
+        Preferences prefs = NbPreferences.forModule(DecompileToolbar.class);
+        
+        return prefs.node(KEY_EXTRA_PARAMS_HISTORY);
+    }
+
+    private ComboBoxModel<String> createModel() {
+        if (masterModel == null) {
+            masterModel = new DefaultComboBoxModel<>();
+
+            try {
+                Preferences prefs = getHistoryNode();
+                List<String> keys = new ArrayList<>(Arrays.asList(prefs.keys()));
+
+                Collections.sort(keys);
+
+                for (String key : keys) {
+                    masterModel.addElement(prefs.get(key, ""));
+                }
+            } catch (BackingStoreException ex) {
+                Exceptions.printStackTrace(ex);
+            }
+        }
+
+        return new DelegatingModel(masterModel);
+    }
+
+    private static void storeMasterData() {
+        try {
+            Preferences prefs = getHistoryNode();
+
+            prefs.clear();
+
+            for (int i = 0; i < masterModel.getSize(); i++) {
+                prefs.put(Integer.toString(i), masterModel.getElementAt(i));
+            }
+        } catch (BackingStoreException ex) {
+            Exceptions.printStackTrace(ex);
+        }
+    }
+
+    /**
+     * This method is called from within the constructor to initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is always
+     * regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        jLabel1 = new javax.swing.JLabel();
+        compiler = new javax.swing.JComboBox();
+        jLabel2 = new javax.swing.JLabel();
+        decompiler = new javax.swing.JComboBox();
+        jLabel3 = new javax.swing.JLabel();
+        extraOptions = new javax.swing.JComboBox();
+
+        org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(DecompileToolbar.class, "DecompileToolbar.jLabel1.text")); // NOI18N
+
+        compiler.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
+
+        org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(DecompileToolbar.class, "DecompileToolbar.jLabel2.text")); // NOI18N
+
+        decompiler.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
+
+        org.openide.awt.Mnemonics.setLocalizedText(jLabel3, org.openide.util.NbBundle.getMessage(DecompileToolbar.class, "DecompileToolbar.jLabel3.text")); // NOI18N
+
+        extraOptions.setEditable(true);
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
+        this.setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addComponent(jLabel1)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(compiler, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+                .addComponent(jLabel2)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(decompiler, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+                .addComponent(jLabel3)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(extraOptions, 0, 338, Short.MAX_VALUE))
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                .addComponent(jLabel1)
+                .addComponent(compiler, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addComponent(jLabel2)
+                .addComponent(decompiler, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addComponent(jLabel3)
+                .addComponent(extraOptions, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+        );
+    }// </editor-fold>//GEN-END:initComponents
+
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JComboBox compiler;
+    private javax.swing.JComboBox decompiler;
+    private javax.swing.JComboBox extraOptions;
+    private javax.swing.JLabel jLabel1;
+    private javax.swing.JLabel jLabel2;
+    private javax.swing.JLabel jLabel3;
+    // End of variables declaration//GEN-END:variables
+
+    private static class DelegatingModel implements ComboBoxModel<String>, ListDataListener {
+        private final ComboBoxModel<String> master;
+        private final List<ListDataListener> listeners = new ArrayList<>();
+
+        private Object selected;
+
+        public DelegatingModel(ComboBoxModel<String> master) {
+            this.master = master;
+            this.master.addListDataListener(WeakListeners.create(ListDataListener.class, this, master));
+        }
+
+        @Override
+        public void setSelectedItem(Object anItem) {
+            this.selected = anItem;
+            ListDataEvent del = new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, -1, -1);
+
+            for (ListDataListener l : listeners) {
+                l.contentsChanged(del);
+            }
+        }
+
+        @Override
+        public Object getSelectedItem() {
+            return selected;
+        }
+
+        @Override
+        public int getSize() {
+            return master.getSize();
+        }
+
+        @Override
+        public String getElementAt(int index) {
+            return master.getElementAt(index);
+        }
+
+        @Override
+        public void addListDataListener(ListDataListener l) {
+            listeners.add(l);
+        }
+
+        @Override
+        public void removeListDataListener(ListDataListener l) {
+            listeners.remove(l);
+        }
+
+        @Override
+        public void intervalAdded(ListDataEvent e) {
+            ListDataEvent del = new ListDataEvent(this, e.getType(), e.getIndex0(), e.getIndex1());
+
+            for (ListDataListener l : listeners) {
+                l.intervalAdded(del);
+            }
+        }
+
+        @Override
+        public void intervalRemoved(ListDataEvent e) {
+            ListDataEvent del = new ListDataEvent(this, e.getType(), e.getIndex0(), e.getIndex1());
+
+            for (ListDataListener l : listeners) {
+                l.intervalRemoved(del);
+            }
+        }
+
+        @Override
+        public void contentsChanged(ListDataEvent e) {
+            ListDataEvent del = new ListDataEvent(this, e.getType(), e.getIndex0(), e.getIndex1());
+
+            for (ListDataListener l : listeners) {
+                l.contentsChanged(del);
+            }
+        }
+    }
+}
diff --git a/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/DecompiledTab.java b/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/DecompiledTab.java
new file mode 100644
index 0000000..e147644
--- /dev/null
+++ b/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/DecompiledTab.java
@@ -0,0 +1,474 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.debugjavac;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.util.Map;
+import java.util.WeakHashMap;
+import javax.swing.Action;
+import javax.swing.JComponent;
+import javax.swing.JEditorPane;
+import javax.swing.JScrollPane;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+import javax.swing.text.JTextComponent;
+import javax.swing.text.StyledDocument;
+import org.netbeans.api.annotations.common.CheckForNull;
+import org.netbeans.api.editor.EditorRegistry;
+import org.netbeans.api.editor.mimelookup.MimeRegistration;
+import org.netbeans.api.java.source.CancellableTask;
+import org.netbeans.api.java.source.CompilationInfo;
+import org.netbeans.api.java.source.JavaSource.Phase;
+import org.netbeans.api.java.source.JavaSource.Priority;
+import org.netbeans.api.java.source.JavaSourceTaskFactory;
+import org.netbeans.api.java.source.support.EditorAwareJavaSourceTaskFactory;
+import org.netbeans.core.spi.multiview.CloseOperationState;
+import org.netbeans.core.spi.multiview.MultiViewElement;
+import org.netbeans.core.spi.multiview.MultiViewElementCallback;
+import org.netbeans.editor.GuardedDocument;
+import org.netbeans.modules.editor.NbEditorDocument;
+import org.netbeans.modules.editor.NbEditorKit;
+import org.netbeans.modules.editor.NbEditorUtilities;
+import org.netbeans.modules.java.debugjavac.Decompiler.Input;
+import org.netbeans.modules.java.debugjavac.Decompiler.Result;
+import org.netbeans.modules.parsing.api.Source;
+import org.netbeans.modules.parsing.spi.TaskIndexingMode;
+import org.netbeans.spi.editor.errorstripe.UpToDateStatus;
+import org.netbeans.spi.editor.errorstripe.UpToDateStatusProvider;
+import org.netbeans.spi.editor.errorstripe.UpToDateStatusProviderFactory;
+import org.openide.awt.UndoRedo;
+import org.openide.cookies.EditorCookie;
+import org.openide.cookies.SaveCookie;
+import org.openide.filesystems.FileAttributeEvent;
+import org.openide.filesystems.FileChangeAdapter;
+import org.openide.filesystems.FileChangeListener;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileUtil;
+import org.openide.loaders.DataObject;
+import org.openide.text.NbDocument;
+import org.openide.util.Exceptions;
+import org.openide.util.Lookup;
+import org.openide.util.RequestProcessor;
+import org.openide.util.lookup.ServiceProvider;
+import org.openide.windows.TopComponent;
+
+/**
+ *
+ * @author lahvac
+ */
+public class DecompiledTab {
+
+    public static final String PROP_EXTRA_PARAMS = DecompiledTab.class.getName() + ".extraParams";
+    
+    private static final String ATTR_DECOMPILED = "decompiled-temporary";
+    private static final Map<FileObject, FileObject> source2Decompiled = new WeakHashMap<>();
+    private static final RequestProcessor DECOMPILE_RUNNER = new RequestProcessor(DecompiledTab.class.getName(), 1, false, false);
+
+    public static synchronized FileObject findDecompiled(FileObject source) {
+        return findDecompiled(source, true);
+    }
+    
+    private static synchronized FileObject findDecompiled(FileObject source, boolean create) {
+        FileObject result = source2Decompiled.get(source);
+
+        if (result == null && create) {
+            try {
+                FileObject decompiledFO = FileUtil.createMemoryFileSystem().getRoot().createData(source.getName(), "djava");
+
+                decompiledFO.setAttribute(ATTR_DECOMPILED, Boolean.TRUE);
+
+                source2Decompiled.put(source, result = decompiledFO);
+            } catch (IOException ex) {
+                throw new IllegalStateException(ex);
+            }
+        }
+
+        return result;
+    }
+    
+    private static @CheckForNull Document decompiledCodeDocument(FileObject file) {
+        return decompiledCodeDocument(file, true);
+    }
+
+    private static @CheckForNull Document decompiledCodeDocument(FileObject file, boolean create) {
+        try {
+            FileObject decompiled = findDecompiled(file, create);
+
+            if (decompiled == null) return null;
+            
+            DataObject decompiledDO = DataObject.find(decompiled);
+            EditorCookie ec = decompiledDO.getLookup().lookup(EditorCookie.class);
+            return ec.openDocument();
+        } catch (IOException ex) {
+            Exceptions.printStackTrace(ex);
+            return null;
+        }
+    }
+    
+    private static DecompilerDescription findDecompiler(String id) throws MalformedURLException {
+        for (DecompilerDescription decompiler : DecompilerDescription.getDecompilers()) {
+            if (id.equals(decompiler.id)) return decompiler;
+        }
+
+        return null;
+    }
+
+    private static void decompileIntoDocumentLater(final FileObject source) {
+        DECOMPILE_RUNNER.post(new Runnable() {
+            @Override public void run() {
+                doDecompileIntoDocument(source);
+            }
+        });
+        
+    }
+
+    private static void doDecompileIntoDocument(FileObject source) {
+        FileObject decompiled = findDecompiled(source, true);
+        final Document doc = decompiledCodeDocument(source);
+        
+        if (doc == null || doc.getProperty(DECOMPILE_TAB_ACTIVE) != Boolean.TRUE) return ;
+        
+        try {
+            Object compilerDescription = decompiled.getAttribute(CompilerDescription.class.getName());
+            Object decompilerId = decompiled.getAttribute(DecompilerDescription.class.getName());
+            Object extraParams = decompiled.getAttribute(PROP_EXTRA_PARAMS);
+            
+            if (!(compilerDescription instanceof CompilerDescription) || !(decompilerId instanceof String)) {
+                return ;
+            }
+
+            if (!(extraParams instanceof String) || extraParams == null) {
+                extraParams = "";
+            }
+
+            final String decompiledCode;
+            
+            if (((CompilerDescription) compilerDescription).isValid()) {
+                final String code = Source.create(source).createSnapshot().getText().toString();
+                UpToDateStatusProviderImpl.get(doc).update(UpToDateStatus.UP_TO_DATE_PROCESSING);
+                DecompilerDescription decompiler = findDecompiler((String) decompilerId);
+                Result decompileResult = ((CompilerDescription) compilerDescription).decompile(decompiler, new Input(code, Utilities.commandLineParameters(source, (String) extraParams)));
+                if (decompileResult.exception != null) {
+                    decompiledCode = "#Section(text/plain) Ooops, an exception occurred while decompiling:\n" + decompileResult.exception;
+                } else {
+                    decompiledCode = (decompileResult.decompiledOutput != null ? "#Section(" + decompileResult.decompiledMimeType + ") Output:\n" + decompileResult.decompiledOutput + "\n" : "") +
+                                     (decompileResult.compileErrors != null ? "#Section(text/plain) Processing Errors:\n" + decompileResult.compileErrors + "\n" : "");
+                }
+            } else {
+                decompiledCode = "Unusable compiler";
+            }
+
+            NbDocument.runAtomic((StyledDocument) doc, new Runnable() {
+                @Override public void run() {
+                    try {
+                        doc.remove(0, doc.getLength());
+                        if (doc instanceof GuardedDocument) {
+                            ((GuardedDocument) doc).getGuardedBlockChain().removeEmptyBlocks();
+                        }
+                        doc.insertString(0, decompiledCode, null);
+                        if (doc instanceof GuardedDocument) {
+                            ((GuardedDocument) doc).getGuardedBlockChain().addBlock(0, doc.getLength(), true);
+                        }
+                    } catch (BadLocationException ex) {
+                        Exceptions.printStackTrace(ex);
+                    }
+                }
+            });
+            
+            SaveCookie sc = DataObject.find(decompiled).getLookup().lookup(SaveCookie.class);
+            
+            if (sc != null) sc.save();
+
+            UpToDateStatusProviderImpl.get(doc).update(UpToDateStatus.UP_TO_DATE_OK);
+        } catch (IOException ex) {
+            Exceptions.printStackTrace(ex);
+        }
+    }
+
+    private static final String DECOMPILE_TAB_ACTIVE = "decompile-tab-active";
+    
+    @MultiViewElement.Registration(
+        displayName="Decompile",
+//        iconBase="org/netbeans/modules/java/resources/class.gif",
+        persistenceType=TopComponent.PERSISTENCE_ONLY_OPENED,
+        preferredID="java.decompile",
+        mimeType="text/x-java",
+        position=5000
+    )
+    public static MultiViewElement createMultiViewEditorElement(Lookup context) {
+        final DataObject d = context.lookup(DataObject.class);
+        final FileObject decompiled = findDecompiled(d.getPrimaryFile(), true);
+        return new MultiViewElement() {
+            private JEditorPane pane;
+            private JComponent scrollPane;
+            private final FileChangeListener fileListener = new FileChangeAdapter() {
+                @Override public void fileAttributeChanged(FileAttributeEvent fe) {
+                    decompileIntoDocumentLater(d.getPrimaryFile());
+                }
+            };
+            @Override
+            public JComponent getVisualRepresentation() {
+                if (pane == null) {
+                    pane = new JEditorPane();
+                    pane.setContentType("text/x-java-decompiled");
+                    pane.setEditorKit(new NbEditorKit() {
+                        @Override public String getContentType() {
+                            return "text/x-java-decompiled";
+                        }
+                    });
+                    Document doc = decompiledCodeDocument(d.getPrimaryFile());
+                    if (doc != null)
+                        pane.setDocument(doc);
+                    scrollPane = doc instanceof NbEditorDocument ? (JComponent) ((NbEditorDocument) doc).createEditor(pane) : new JScrollPane(pane);
+                }
+                return scrollPane;
+            }
+
+            private DecompileToolbar toolbar;
+            @Override
+            public JComponent getToolbarRepresentation() {
+                if (toolbar == null) {
+                    FileObject decompiled = findDecompiled(d.getPrimaryFile(), true);
+                    toolbar = new DecompileToolbar(decompiled, d.getPrimaryFile());
+                }
+                return toolbar;
+            }
+
+            @Override
+            public Action[] getActions() {
+                return new Action[0];
+            }
+
+            @Override
+            public Lookup getLookup() {
+                return Lookup.EMPTY;
+            }
+
+            @Override
+            public void componentOpened() {
+            }
+
+            @Override
+            public void componentClosed() {
+            }
+
+            @Override
+            public void componentShowing() {
+                Document doc = decompiledCodeDocument(d.getPrimaryFile());
+                if (doc != null) doc.putProperty(DECOMPILE_TAB_ACTIVE, true);
+                decompiled.addFileChangeListener(fileListener);
+                decompileIntoDocumentLater(d.getPrimaryFile());
+            }
+
+            @Override
+            public void componentHidden() {
+                Document doc = decompiledCodeDocument(d.getPrimaryFile());
+                if (doc != null) doc.putProperty(DECOMPILE_TAB_ACTIVE, null);
+                decompiled.removeFileChangeListener(fileListener);
+            }
+
+            @Override
+            public void componentActivated() {
+            }
+
+            @Override
+            public void componentDeactivated() {
+            }
+
+            @Override
+            public UndoRedo getUndoRedo() {
+                return null;
+            }
+
+            @Override
+            public void setMultiViewCallback(MultiViewElementCallback callback) {
+            }
+
+            @Override
+            public CloseOperationState canCloseElement() {
+                return CloseOperationState.STATE_OK;
+            }
+            
+        };
+    }
+
+    static {
+        EditorRegistry.addPropertyChangeListener(new DocL());
+    }
+
+    private static final class DocL implements PropertyChangeListener, DocumentListener {
+
+        private Document lastFocused;
+
+        @Override public void propertyChange(PropertyChangeEvent evt) {
+            JTextComponent fc = EditorRegistry.focusedComponent();
+            Document doc = fc != null ? fc.getDocument() : null;
+
+            if (doc == lastFocused) return ;
+
+            if (lastFocused != null) {
+                lastFocused.removeDocumentListener(this);
+            }
+
+            if (doc != null) {
+                doc.addDocumentListener(this);
+            }
+
+            lastFocused = doc;
+        }
+
+        @Override
+        public void insertUpdate(DocumentEvent e) {
+            update(e);
+        }
+
+        @Override
+        public void removeUpdate(DocumentEvent e) {
+            update(e);
+        }
+
+        private void update(DocumentEvent e) {
+            FileObject file = NbEditorUtilities.getFileObject(e.getDocument());
+
+            if (file == null) return ;
+
+            Document doc = decompiledCodeDocument(file, false);
+
+            if (doc == null) return ;
+
+            UpToDateStatusProviderImpl.get(doc).update(UpToDateStatus.UP_TO_DATE_DIRTY);
+        }
+
+        @Override
+        public void changedUpdate(DocumentEvent e) {
+        }
+
+    }
+
+    private static final class Updater implements CancellableTask<CompilationInfo> {
+        @Override public void run(CompilationInfo parameter) throws Exception {
+            doDecompileIntoDocument(parameter.getFileObject());
+//            FileObject sourceFile = parameter.getFileObject();
+////            if (sourceFile.getAttribute(ATTR_DECOMPILED) == Boolean.TRUE) return;
+//            final FileObject decompiled = findDecompiled(sourceFile, false);
+//            
+//            if (decompiled == null) return ;
+//            
+//            final ElementHandle<?> handle = ElementHandle.create(parameter.getTopLevelElements().get(0));
+//
+//            JavaSource.create(parameter.getClasspathInfo(), decompiled).runModificationTask(new Task<WorkingCopy>() {
+//                @Override public void run(WorkingCopy copy) throws Exception {
+//                    copy.toPhase(Phase.RESOLVED);
+//
+//                    copy.rewrite(copy.getCompilationUnit(), CodeGenerator.generateCode(copy, (TypeElement) handle.resolve(copy)));
+//                }
+//            }).commit();
+//            
+//            SaveCookie sc = DataObject.find(decompiled).getLookup().lookup(SaveCookie.class);
+//            
+//            if (sc != null) sc.save();
+        }
+
+        @Override public void cancel() {
+        }
+
+    }
+
+    @ServiceProvider(service=JavaSourceTaskFactory.class)
+    public static final class UpdaterFactory extends EditorAwareJavaSourceTaskFactory {
+
+        public UpdaterFactory() {
+            super(Phase.RESOLVED, Priority.LOW, TaskIndexingMode.ALLOWED_DURING_SCAN);
+        }
+
+        @Override
+        protected CancellableTask<CompilationInfo> createTask(FileObject file) {
+            return new Updater();
+        }
+
+    }
+
+   @MimeRegistration(mimeType="text/x-java-decompiled", service=UpToDateStatusProviderFactory.class)
+     public static final class UpToDateStatusProviderFactoryImpl implements UpToDateStatusProviderFactory {
+        @Override public UpToDateStatusProvider createUpToDateStatusProvider(Document document) {
+            return UpToDateStatusProviderImpl.get(document);
+        }
+    }
+
+    private static final class UpToDateStatusProviderImpl extends UpToDateStatusProvider {
+
+        public static UpToDateStatusProviderImpl get(Document doc) {
+            UpToDateStatusProviderImpl result = (UpToDateStatusProviderImpl) doc.getProperty(UpToDateStatusProviderImpl.class);
+
+            if (result == null) {
+                result = new UpToDateStatusProviderImpl(doc);
+            }
+
+            return result;
+        }
+
+        private final Document doc;
+
+        private UpToDateStatusProviderImpl(Document doc) {
+            this.doc = doc;
+        }
+
+        @Override
+        public UpToDateStatus getUpToDate() {
+            UpToDateStatus status = (UpToDateStatus) doc.getProperty(UpToDateStatusProviderImpl.class.getName() + "-status-value");
+
+            if (status == null) status = UpToDateStatus.UP_TO_DATE_DIRTY;
+
+            return status;
+        }
+
+        private void update(UpToDateStatus newValue) {
+            UpToDateStatus oldValue = getUpToDate();
+
+            doc.putProperty(UpToDateStatusProviderImpl.class.getName() + "-status-value", newValue);
+            firePropertyChange(PROP_UP_TO_DATE, oldValue, newValue);
+
+            //TODO: the event above does not always repaint the error stripe, workarounding:
+            NbDocument.runAtomic((StyledDocument) doc, new Runnable() {
+                @Override public void run() {
+                    try {
+                        doc.insertString(0, " ", null);
+                        doc.remove(0, 1);
+                    } catch (BadLocationException ex) {
+                        Exceptions.printStackTrace(ex);
+                    }
+                }
+            });
+
+            try {
+                FileObject decompiledFO = NbEditorUtilities.getFileObject(doc);
+                SaveCookie sc = decompiledFO != null ? DataObject.find(decompiledFO).getLookup().lookup(SaveCookie.class) : null;
+
+                if (sc != null) sc.save();
+            } catch (IOException ex) {
+                Exceptions.printStackTrace(ex);
+            }
+        }
+    }
+}
diff --git a/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/Decompiler.java b/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/Decompiler.java
new file mode 100644
index 0000000..c02a0da
--- /dev/null
+++ b/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/Decompiler.java
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.debugjavac;
+
+import java.util.List;
+
+/**
+ *
+ * @author lahvac
+ */
+public interface Decompiler {
+    public Result decompile(Input input);
+
+    public final class Input {
+        public String source;
+        public List<String> params;
+
+        public Input() {
+        }
+
+        public Input(String source, List<String> params) {
+            this.source = source;
+            this.params = params;
+        }
+
+        public String getSource() {
+            return source;
+        }
+
+        public void setSource(String source) {
+            this.source = source;
+        }
+
+        public List<String> getParams() {
+            return params;
+        }
+
+        public void setParams(List<String> params) {
+            this.params = params;
+        }
+
+    }
+//    public final class Input {
+//        public final String source;
+//        public final List<String> params;
+//        public Input(String source, List<String> params) {
+//            this.source = source;
+//            this.params = params;
+//        }
+//    }
+    public final class Result {
+        public String compileErrors;
+        public String decompiledOutput;
+        public String decompiledMimeType;
+        public String exception;
+
+        public Result() {
+        }
+
+        public Result(String compileErrors, String decompiledOutput, String decompiledMimeType) {
+            this.compileErrors = compileErrors.trim().isEmpty() ? null : compileErrors;
+            this.decompiledOutput = decompiledOutput.trim().isEmpty() ? null : decompiledOutput;
+            this.decompiledMimeType = decompiledMimeType;
+        }
+
+        public Result(String exception) {
+            this.exception = exception;
+        }
+
+        public String getCompileErrors() {
+            return compileErrors;
+        }
+
+        public void setCompileErrors(String compileErrors) {
+            this.compileErrors = compileErrors;
+        }
+
+        public String getDecompiledOutput() {
+            return decompiledOutput;
+        }
+
+        public void setDecompiledOutput(String decompiledOutput) {
+            this.decompiledOutput = decompiledOutput;
+        }
+
+        public String getDecompiledMimeType() {
+            return decompiledMimeType;
+        }
+
+        public void setDecompiledMimeType(String decompiledMimeType) {
+            this.decompiledMimeType = decompiledMimeType;
+        }
+
+        public String getException() {
+            return exception;
+        }
+
+        public void setException(String exception) {
+            this.exception = exception;
+        }
+    }
+//    public final class Result {
+//        public final String compileErrors;
+//        public final String decompiledOutput;
+//        public final String decompiledMimeType;
+//        public Result(String compileErrors, String decompiledOutput, String decompiledMimeType) {
+//            this.compileErrors = compileErrors.trim().isEmpty() ? null : compileErrors;
+//            this.decompiledOutput = decompiledOutput.trim().isEmpty() ? null : decompiledOutput;
+//            this.decompiledMimeType = decompiledMimeType;
+//        }
+//    }
+}
diff --git a/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/DecompilerDescription.java b/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/DecompilerDescription.java
new file mode 100644
index 0000000..0f4bfe8
--- /dev/null
+++ b/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/DecompilerDescription.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.debugjavac;
+
+import java.util.Arrays;
+
+/**
+ *
+ * @author lahvac
+ */
+public final class DecompilerDescription {
+    public final String id;
+    public final String displayName;
+    public final String className;
+
+    private DecompilerDescription(String id, String displayName, String className) {
+        this.id = id;
+        this.displayName = displayName;
+        this.className = className;
+    }
+
+    public Decompiler createDecompiler(ClassLoader from) {
+        try {
+            Class<?> loadClass = from.loadClass(className);
+
+            return Decompiler.class.cast(loadClass.newInstance());
+        } catch (ReflectiveOperationException ex) {
+            throw new IllegalStateException(ex);
+        }
+    }
+
+    private static final Iterable<? extends DecompilerDescription> DECOMPILERS = Arrays.asList(
+        new DecompilerDescription("javap", "javap", "org.netbeans.modules.java.debugjavac.impl.JavapDecompilerImpl"),
+        new DecompilerDescription("lower", "Desugared source", "org.netbeans.modules.java.debugjavac.impl.DesugarDecompilerImpl")
+    );
+
+    public static Iterable<? extends DecompilerDescription> getDecompilers() {
+        return DECOMPILERS;
+    }
+}
diff --git a/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/TopLevelLexer.java b/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/TopLevelLexer.java
new file mode 100644
index 0000000..548bfe8
--- /dev/null
+++ b/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/TopLevelLexer.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.debugjavac;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.netbeans.api.lexer.Token;
+import org.netbeans.spi.lexer.Lexer;
+import org.netbeans.spi.lexer.LexerInput;
+import org.netbeans.spi.lexer.LexerRestartInfo;
+import org.netbeans.spi.lexer.TokenFactory;
+
+/**
+ *
+ * @author lahvac
+ */
+public class TopLevelLexer implements Lexer<TopLevelTokenId> {
+    
+    private static final Pattern SECTION_PATTERN = Pattern.compile("#Section\\(([^)]*)\\)[^\n]*\n");
+    private final TokenFactory<TopLevelTokenId> factory;
+    private final LexerInput input;
+    private TopLevelTokenId futureToken;
+
+    public TopLevelLexer(LexerRestartInfo<TopLevelTokenId> restart) {
+        this.factory = restart.tokenFactory();
+        this.input = restart.input();
+        this.futureToken = restart.state() != null ? (TopLevelTokenId) restart.state() : TopLevelTokenId.OTHER;
+    }
+    
+    @Override
+    public Token<TopLevelTokenId> nextToken() {
+        StringBuilder text = new StringBuilder();
+        int read;
+        
+        while ((read = input.read()) != LexerInput.EOF) {
+            text.append((char) read);
+            
+            Matcher m = SECTION_PATTERN.matcher(text);
+            
+            if (m.find()) {
+                if (m.start() == 0) {
+                    String mimeType = m.group(1);
+                    
+                    switch (mimeType) {
+                        case "text/x-java": futureToken = TopLevelTokenId.JAVA; break;
+                        case "text/x-java-bytecode": futureToken = TopLevelTokenId.ASM; break;
+                        default: futureToken = TopLevelTokenId.OTHER; break;
+                    }
+                    
+                    return factory.createToken(TopLevelTokenId.SECTION_HEADER);
+                } else {
+                    input.backup(input.readLength() - m.start());
+                    break;
+                }
+            }
+        }
+        
+        if (input.readLength() > 0)
+            return factory.createToken(futureToken);
+        
+        return null;
+    }
+
+    @Override
+    public Object state() {
+        return futureToken;
+    }
+
+    @Override
+    public void release() {}
+    
+}
diff --git a/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/TopLevelTokenId.java b/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/TopLevelTokenId.java
new file mode 100644
index 0000000..5c1d401
--- /dev/null
+++ b/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/TopLevelTokenId.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.debugjavac;
+
+import java.util.Arrays;
+import java.util.Collection;
+import org.netbeans.api.editor.mimelookup.MimeRegistration;
+import org.netbeans.api.lexer.InputAttributes;
+import org.netbeans.api.lexer.Language;
+import org.netbeans.api.lexer.LanguagePath;
+import org.netbeans.api.lexer.Token;
+import org.netbeans.api.lexer.TokenId;
+import org.netbeans.spi.lexer.EmbeddingPresence;
+import org.netbeans.spi.lexer.LanguageEmbedding;
+import org.netbeans.spi.lexer.LanguageHierarchy;
+import org.netbeans.spi.lexer.Lexer;
+import org.netbeans.spi.lexer.LexerRestartInfo;
+
+/**
+ *
+ * @author lahvac
+ */
+public enum TopLevelTokenId implements TokenId {
+    SECTION_HEADER,
+    JAVA,
+    ASM,
+    OTHER;
+
+    @Override
+    public String primaryCategory() {
+        return this == SECTION_HEADER ? "comment" : "code";
+    }
+    
+    private static final Language<TopLevelTokenId> LANGUAGE = new LanguageHierarchy<TopLevelTokenId>() {
+        @Override protected Collection<TopLevelTokenId> createTokenIds() {
+            return Arrays.asList(TopLevelTokenId.values());
+        }
+        @Override protected Lexer<TopLevelTokenId> createLexer(LexerRestartInfo<TopLevelTokenId> info) {
+            return new TopLevelLexer(info);
+        }
+        @Override protected String mimeType() {
+            return "text/x-java-decompiled";
+        }
+        @Override protected LanguageEmbedding<?> embedding(Token<TopLevelTokenId> token, LanguagePath languagePath, InputAttributes inputAttributes) {
+            switch (token.id()) {
+                case JAVA:
+                    return LanguageEmbedding.create(Language.find("text/x-java"), 0, 0);
+                default:
+                    return null;
+            }
+        }
+
+    }.language();
+    
+    @MimeRegistration(mimeType="text/x-java-decompiled", service=Language.class)
+    public static final Language<TopLevelTokenId> language() {
+        return LANGUAGE;
+    }
+}
diff --git a/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/Utilities.java b/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/Utilities.java
new file mode 100644
index 0000000..dfd635c
--- /dev/null
+++ b/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/Utilities.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.debugjavac;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.netbeans.api.java.classpath.ClassPath;
+import org.netbeans.api.java.classpath.ClassPath.PathConversionMode;
+import org.netbeans.api.java.platform.JavaPlatform;
+import org.netbeans.api.java.queries.SourceLevelQuery;
+import org.openide.filesystems.FileObject;
+
+/**
+ *
+ * @author lahvac
+ */
+public class Utilities {
+    public static List<String> commandLineParameters(FileObject source, String extraParameters) throws IOException {
+        List<String> extraParams = new ArrayList<>();
+        Set<String> extraParamsSet = new HashSet<>();
+        StringBuilder param = new StringBuilder();
+        char currentQuote = '\0';
+        for (char c : extraParameters.toCharArray()) {
+            switch (c) {
+                case '\r': continue;
+                case  ' ': case '\n': case '\t':
+                    if (currentQuote == '\0') {
+                        String p = param.toString();
+                        param.delete(0, param.length());
+                        extraParams.add(p);
+                        extraParamsSet.add(p);
+                        continue;
+                    }
+                    break;
+                case '"':
+                    if (currentQuote == '"') {
+                        currentQuote = '\0';
+                        continue;
+                    } else if (currentQuote == '\0') {
+                        currentQuote = '"';
+                        continue;
+                    }
+                    break;
+                case '\'':
+                    if (currentQuote == '\'') {
+                        currentQuote = '\0';
+                        continue;
+                    } else if (currentQuote == '\0') {
+                        currentQuote = '\'';
+                        continue;
+                    }
+                    break;
+            }
+
+            param.append(c);
+        }
+        if (param.length() > 0) {
+            String p = param.toString();
+            extraParams.add(p);
+            extraParamsSet.add(p);
+        }
+        List<String> result = new ArrayList<>();
+//        if (!extraParamsSet.contains("-bootclasspath")) {
+//            ClassPath boot = ClassPath.getClassPath(source, ClassPath.BOOT);
+//            if (boot == null) boot = JavaPlatform.getDefault().getBootstrapLibraries();
+//            result.add("-bootclasspath");
+//            result.add(boot.toString(PathConversionMode.PRINT));
+//        }
+        if (!extraParamsSet.contains("-classpath")) {
+            ClassPath compile = ClassPath.getClassPath(source, ClassPath.COMPILE);
+            if (compile == null) compile = ClassPath.EMPTY;
+            result.add("-classpath");
+            result.add(compile.toString(PathConversionMode.PRINT));
+        }
+        String sourceLevel = SourceLevelQuery.getSourceLevel(source);
+        sourceLevel = sourceLevel != null ? sourceLevel : "1.8";
+        if (!extraParamsSet.contains("-source")) {
+            result.add("-source");
+            result.add(sourceLevel);
+        }
+        if (!extraParamsSet.contains("-target")) {
+            result.add("-target");
+            result.add(sourceLevel);
+        }
+
+        result.addAll(extraParams);
+        
+        return result;
+    }
+    
+}
diff --git a/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/impl/DesugarDecompilerImpl.java b/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/impl/DesugarDecompilerImpl.java
new file mode 100644
index 0000000..016ad4b
--- /dev/null
+++ b/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/impl/DesugarDecompilerImpl.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.debugjavac.impl;
+
+import com.sun.source.tree.ImportTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.tree.Tree.Kind;
+import com.sun.source.util.JavacTask;
+import com.sun.tools.javac.api.JavacTaskImpl;
+import com.sun.tools.javac.api.JavacTool;
+import com.sun.tools.javac.comp.AttrContext;
+import com.sun.tools.javac.comp.Env;
+import com.sun.tools.javac.main.JavaCompiler;
+import com.sun.tools.javac.tree.JCTree.JCClassDecl;
+import com.sun.tools.javac.util.Context.Factory;
+import com.sun.tools.javac.util.Pair;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Arrays;
+import java.util.Queue;
+import javax.tools.DiagnosticListener;
+import javax.tools.JavaFileObject;
+import org.netbeans.modules.java.debugjavac.Decompiler;
+
+/**
+ *
+ * @author lahvac
+ */
+public class DesugarDecompilerImpl implements Decompiler {
+
+    @Override
+    public Result decompile(Input input) {
+        StringWriter errors = new StringWriter();
+        StringWriter decompiled = new StringWriter();
+        
+        try {
+            DiagnosticListener<JavaFileObject> errorsListener = Utilities.errorReportingDiagnosticListener(errors);
+            JavaFileObject file = Utilities.sourceFileObject(input.source);
+            JavacTask task = JavacTool.create().getTask(null, 
+                    null,
+                    errorsListener, Utilities.augmentCommandLineParameters(input), null, Arrays.asList(file));
+
+            JavaCompilerOverride.preRegister(((JavacTaskImpl) task).getContext(), decompiled);
+            task.generate();
+        } catch (IOException ex) {
+            ex.printStackTrace(new PrintWriter(errors));
+        }
+        
+        return new Result(errors.toString(), decompiled.toString().trim(), "text/x-java");
+    }
+    
+    static class JavaCompilerOverride extends JavaCompiler {
+        public static void preRegister(com.sun.tools.javac.util.Context context, final StringWriter out) {
+            context.put(compilerKey, new Factory<JavaCompiler>() {
+                @Override public JavaCompiler make(com.sun.tools.javac.util.Context c) {
+                    return new JavaCompilerOverride(out, c);
+                }
+            });
+        }
+        private final StringWriter out;
+
+        public JavaCompilerOverride(StringWriter out, com.sun.tools.javac.util.Context context) {
+            super(context);
+            this.out = out;
+        }
+        
+        @Override public void generate(Queue<Pair<Env<AttrContext>, JCClassDecl>> queue, Queue<JavaFileObject> results) {
+            Pair<Env<AttrContext>, JCClassDecl> first = queue.peek();
+
+            if (first != null) {
+                if (first.fst.toplevel.getPackageName() != null) {
+                    out.write("package ");
+                    out.write(first.fst.toplevel.getPackageName().toString());
+                    out.write(";\n\n");
+                }
+
+                boolean hasImports = false;
+                
+                for (Tree importCandidate : first.fst.toplevel.defs) {
+                    if (importCandidate != null && importCandidate.getKind() == Kind.IMPORT) {
+                        out.write("import ");
+                        ImportTree importTree = (ImportTree) importCandidate;
+                        if (importTree.isStatic()) {
+                            out.write("static ");
+                        }
+                        out.write(importTree.getQualifiedIdentifier().toString());
+                        out.write(";\n");
+                        hasImports = true;
+                    }
+                }
+
+                if (hasImports) {
+                    out.write("\n");
+                }
+
+                for (Pair<Env<AttrContext>, JCClassDecl> q : queue) {
+                    out.write(q.snd.toString());
+                    out.write("\n");
+                }
+            }
+        }
+    }
+}
diff --git a/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/impl/JavapDecompilerImpl.java b/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/impl/JavapDecompilerImpl.java
new file mode 100644
index 0000000..a6afba7
--- /dev/null
+++ b/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/impl/JavapDecompilerImpl.java
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.debugjavac.impl;
+
+import com.sun.tools.classfile.ConstantPoolException;
+import com.sun.tools.javac.api.JavacTool;
+import com.sun.tools.javap.Context;
+import com.sun.tools.javap.JavapTask;
+import com.sun.tools.javap.JavapTask.BadArgs;
+import com.sun.tools.javap.JavapTask.ClassFileInfo;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import javax.tools.DiagnosticListener;
+import javax.tools.ForwardingJavaFileManager;
+import javax.tools.JavaFileManager;
+import javax.tools.JavaFileManager.Location;
+import javax.tools.JavaFileObject;
+import javax.tools.JavaFileObject.Kind;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import org.netbeans.modules.java.debugjavac.Decompiler;
+import org.openide.util.Exceptions;
+
+/**
+ *
+ * @author lahvac
+ */
+public class JavapDecompilerImpl implements Decompiler {
+
+    @Override
+    public Result decompile(Input input) {
+        StringWriter errors = new StringWriter();
+        StringWriter decompiled = new StringWriter();
+        try {
+            final Map<String, byte[]> bytecode = compile(input, errors);
+
+            if (!bytecode.isEmpty()) {
+                for (final Entry<String, byte[]> e : bytecode.entrySet()) {
+                    class JavapTaskImpl extends JavapTask {
+                        public Context getContext() {
+                            return context;
+                        }
+                    }
+                    JavapTaskImpl t = new JavapTaskImpl();
+                    List<String> options = new ArrayList<String>();
+                    options.add("-private");
+                    options.add("-verbose");
+                    options.add(e.getKey());
+                    t.handleOptions(options.toArray(new String[0]));
+                    t.getContext().put(PrintWriter.class, new PrintWriter(decompiled));
+                    ClassFileInfo cfi = t.read(new SimpleJavaFileObject(URI.create("mem://mem"), Kind.CLASS) {
+                        @Override public InputStream openInputStream() throws IOException {
+                            return new ByteArrayInputStream(e.getValue());
+                        }
+                    });
+
+                    t.write(cfi);
+                }
+            }
+        } catch (IOException | ConstantPoolException ex) {
+            ex.printStackTrace(new PrintWriter(errors));
+        } catch (BadArgs ex) {
+            Exceptions.printStackTrace(ex);
+        }
+        
+        return new Result(errors.toString(), decompiled.toString(), "text/x-java-bytecode");
+    }
+    
+    private static Map<String, byte[]> compile(Input input, final StringWriter errors) throws IOException {
+        DiagnosticListener<JavaFileObject> errorsListener = Utilities.errorReportingDiagnosticListener(errors);
+        StandardJavaFileManager sjfm = JavacTool.create().getStandardFileManager(errorsListener, null, null);
+        final Map<String, ByteArrayOutputStream> class2BAOS = new HashMap<String, ByteArrayOutputStream>();
+
+        JavaFileManager jfm = new ForwardingJavaFileManager<JavaFileManager>(sjfm) {
+            @Override
+            public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, javax.tools.FileObject sibling) throws IOException {
+                final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+                
+                class2BAOS.put(className, buffer);
+                return new SimpleJavaFileObject(sibling.toUri(), kind) {
+                    @Override
+                    public OutputStream openOutputStream() throws IOException {
+                        return buffer;
+                    }
+                };
+            }
+        };
+
+        JavaFileObject file = Utilities.sourceFileObject(input.source);
+        JavacTool.create().getTask(null, jfm, errorsListener, /*XXX:*/Utilities.augmentCommandLineParameters(input), null, Arrays.asList(file)).call();
+
+        Map<String, byte[]> result = new HashMap<String, byte[]>();
+
+        for (Map.Entry<String, ByteArrayOutputStream> e : class2BAOS.entrySet()) {
+            result.put(e.getKey(), e.getValue().toByteArray());
+        }
+
+        return result;
+    }
+    
+}
diff --git a/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/impl/Main.java b/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/impl/Main.java
new file mode 100644
index 0000000..932ec28
--- /dev/null
+++ b/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/impl/Main.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.debugjavac.impl;
+
+import java.beans.XMLDecoder;
+import java.beans.XMLEncoder;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import org.netbeans.modules.java.debugjavac.Decompiler.Input;
+import org.netbeans.modules.java.debugjavac.Decompiler.Result;
+import org.netbeans.modules.java.debugjavac.DecompilerDescription;
+
+/**
+ *
+ * @author lahvac
+ */
+public class Main {
+    public static void main(String... args) {
+        try {
+            Input input;
+
+            try (XMLDecoder decoder = new XMLDecoder(System.in)) {
+                input = (Input) decoder.readObject();
+            }
+
+            String id = args[0];
+
+            for (DecompilerDescription desc : DecompilerDescription.getDecompilers()) {
+                if (id.equals(desc.id)) {
+                    Result result = desc.createDecompiler(Main.class.getClassLoader()).decompile(input);
+                    try (XMLEncoder enc = new XMLEncoder(System.out)) {
+                        enc.writeObject(result);
+                    }
+                    return ;
+                }
+            }
+
+            throw new IllegalStateException("Cannot find: " + id);
+        } catch (Throwable t) {
+            try (XMLEncoder enc = new XMLEncoder(System.out)) {
+                StringWriter sw = new StringWriter();
+                PrintWriter pw = new PrintWriter(sw);
+                t.printStackTrace(pw);
+                pw.close();
+                enc.writeObject(new Result(sw.toString()));
+            }
+        }
+    }
+}
diff --git a/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/impl/Utilities.java b/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/impl/Utilities.java
new file mode 100644
index 0000000..768f01d
--- /dev/null
+++ b/extra/java.debugjavac/src/main/java/org/netbeans/modules/java/debugjavac/impl/Utilities.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.debugjavac.impl;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+import javax.tools.Diagnostic;
+import javax.tools.DiagnosticListener;
+import javax.tools.JavaFileObject;
+import javax.tools.JavaFileObject.Kind;
+import javax.tools.SimpleJavaFileObject;
+import org.netbeans.modules.java.debugjavac.Decompiler.Input;
+
+/**
+ *
+ * @author lahvac
+ */
+public class Utilities {
+    public static List<String> augmentCommandLineParameters(Input input) throws IOException {
+        try {
+            Class.forName("com.sun.tools.javac.comp.Repair");
+            List<String> augmentedParams = new ArrayList<>(input.params);
+            augmentedParams.add("-XDshouldStopPolicy=GENERATE");
+            return augmentedParams;
+        } catch (ClassNotFoundException ex) {
+            //OK
+            return input.params;
+        }
+    }
+    
+    public static JavaFileObject sourceFileObject(final String code) {
+        return new SimpleJavaFileObject(URI.create("mem://mem"), Kind.SOURCE) {
+            @Override
+            public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
+                return code;
+            }
+            @Override public boolean isNameCompatible(String simpleName, Kind kind) {
+                return true;
+            }
+        };
+    }
+    
+    public static DiagnosticListener<JavaFileObject> errorReportingDiagnosticListener(final StringWriter out) {
+        return new DiagnosticListener<JavaFileObject>() {
+            public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
+                if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
+                    out.write(diagnostic.getMessage(null));
+                    out.write("\n");
+                }
+            }
+        };
+    }
+}
diff --git a/extra/java.debugjavac/src/main/nbm/manifest.mf b/extra/java.debugjavac/src/main/nbm/manifest.mf
new file mode 100644
index 0000000..f8a1cfd
--- /dev/null
+++ b/extra/java.debugjavac/src/main/nbm/manifest.mf
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/java/debugjavac/Bundle.properties
+
diff --git a/extra/java.debugjavac/src/main/resources/org/netbeans/modules/java/debugjavac/Bundle.properties b/extra/java.debugjavac/src/main/resources/org/netbeans/modules/java/debugjavac/Bundle.properties
new file mode 100644
index 0000000..fbf3218
--- /dev/null
+++ b/extra/java.debugjavac/src/main/resources/org/netbeans/modules/java/debugjavac/Bundle.properties
@@ -0,0 +1,23 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+#Localized module labels. Defaults taken from POM (<name>, <description>, <groupId>) if unset.
+#OpenIDE-Module-Name=
+#OpenIDE-Module-Short-Description=
+#OpenIDE-Module-Long-Description=
+#OpenIDE-Module-Display-Category=
+#Fri Jan 24 07:23:58 CET 2020