Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
IntelliJ IDEA plugin: project structure, action and class file location
- Loading branch information
Showing
12 changed files
with
243 additions
and
1 deletion.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,24 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<module type="PLUGIN_MODULE" version="4"> | |||
<component name="DevKit.ModuleBuildProperties" url="file://$MODULE_DIR$/src/main/resources/META-INF/plugin.xml" /> | |||
<component name="NewModuleRootManager" inherit-compiler-output="true"> | |||
<exclude-output /> | |||
<content url="file://$MODULE_DIR$"> | |||
<sourceFolder url="file://$MODULE_DIR$/src/main/kotlin" isTestSource="false" /> | |||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" /> | |||
</content> | |||
<orderEntry type="jdk" jdkName="IJ CE 2016.2" jdkType="IDEA JDK" /> | |||
<orderEntry type="sourceFolder" forTests="false" /> | |||
<orderEntry type="module-library" scope="PROVIDED"> | |||
<library> | |||
<CLASSES> | |||
<root url="jar://$MODULE_DIR$/../../lib-compile/byteCodeViewer.jar!/" /> | |||
</CLASSES> | |||
<JAVADOC /> | |||
<SOURCES /> | |||
</library> | |||
</orderEntry> | |||
<orderEntry type="module" module-name="browser_main" /> | |||
<orderEntry type="module" module-name="data_main" /> | |||
</component> | |||
</module> |
169 changes: 169 additions & 0 deletions
169
modules/idea/src/main/kotlin/org/gjt/jclasslib/idea/action.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,169 @@ | |||
/* | |||
This library is free software; you can redistribute it and/or | |||
modify it under the terms of the GNU General Public | |||
License as published by the Free Software Foundation; either | |||
version 2 of the license, or (at your option) any later version. | |||
*/ | |||
|
|||
package org.gjt.jclasslib.idea | |||
|
|||
import com.intellij.byteCodeViewer.ByteCodeViewerManager | |||
import com.intellij.ide.util.JavaAnonymousClassesHelper | |||
import com.intellij.openapi.actionSystem.AnAction | |||
import com.intellij.openapi.actionSystem.AnActionEvent | |||
import com.intellij.openapi.actionSystem.CommonDataKeys | |||
import com.intellij.openapi.actionSystem.DataContext | |||
import com.intellij.openapi.application.ApplicationManager | |||
import com.intellij.openapi.diagnostic.Logger | |||
import com.intellij.openapi.editor.Editor | |||
import com.intellij.openapi.module.Module | |||
import com.intellij.openapi.module.ModuleUtilCore | |||
import com.intellij.openapi.progress.ProgressIndicator | |||
import com.intellij.openapi.progress.ProgressManager | |||
import com.intellij.openapi.progress.Task | |||
import com.intellij.openapi.project.Project | |||
import com.intellij.openapi.roots.CompilerModuleExtension | |||
import com.intellij.openapi.roots.ProjectRootManager | |||
import com.intellij.openapi.ui.Messages | |||
import com.intellij.openapi.util.Computable | |||
import com.intellij.openapi.util.IconLoader | |||
import com.intellij.psi.* | |||
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil | |||
import com.intellij.psi.util.* | |||
import org.gjt.jclasslib.io.ClassFileReader | |||
import org.gjt.jclasslib.structures.ClassFile | |||
import java.io.File | |||
import java.io.FileNotFoundException | |||
import java.io.IOException | |||
import java.io.InputStream | |||
|
|||
class ShowBytecodeAction : AnAction() { | |||
|
|||
override fun update(e: AnActionEvent) { | |||
e.presentation.apply { | |||
isEnabled = getPsiElement(e)?.run { containingFile is PsiClassOwner && ByteCodeViewerManager.getContainingClass(this) != null } ?: false | |||
icon = ICON | |||
} | |||
} | |||
|
|||
override fun actionPerformed(e: AnActionEvent) { | |||
val psiElement = getPsiElement(e) ?: return | |||
val project = e.project ?: return | |||
|
|||
ProgressManager.getInstance().run(object : Task.Backgroundable(project, "Locating class file ...") { | |||
var classFile: ClassFile? = null | |||
var errorMessage: String? = null | |||
|
|||
override fun run(indicator: ProgressIndicator) { | |||
classFile = ApplicationManager.getApplication().runReadAction(Computable<ClassFile> { | |||
try { | |||
getClassFile(psiElement) | |||
} catch(e: FileNotFoundException) { | |||
errorMessage = "Class file could not be found" + (if (e.message.isNullOrBlank()) "" else ": " + e.message) | |||
null | |||
} catch(e: Exception) { | |||
errorMessage = "Error reading class file: " + e.message | |||
null | |||
} | |||
}) | |||
} | |||
|
|||
override fun onSuccess() { | |||
if (!project.isDisposed && errorMessage != null && myTitle != null) { | |||
Messages.showWarningDialog(project, errorMessage, "jclasslib bytecode viewer") | |||
} else { | |||
Messages.showMessageDialog("Got class file " + classFile, "jclasslib", Messages.getInformationIcon()) | |||
//TODO continue | |||
} | |||
} | |||
}) | |||
} | |||
|
|||
private fun getPsiElement(e: AnActionEvent): PsiElement? { | |||
return getPsiElement(e.dataContext, e.project, e.getData(CommonDataKeys.EDITOR)) | |||
} | |||
|
|||
private fun getPsiElement(dataContext: DataContext, project: Project?, editor: Editor?): PsiElement? { | |||
if (project == null) { | |||
return null | |||
} else if (editor == null) { | |||
return dataContext.getData(CommonDataKeys.PSI_ELEMENT) | |||
} else { | |||
val psiFile = PsiUtilBase.getPsiFileInEditor(editor, project) | |||
val injectedEditor = InjectedLanguageUtil.getEditorForInjectedLanguageNoCommit(editor, psiFile) | |||
return injectedEditor?.let { injectedEditor -> | |||
findElementInFile(PsiUtilBase.getPsiFileInEditor(injectedEditor, project), injectedEditor) | |||
} ?: findElementInFile(psiFile, editor) | |||
} | |||
} | |||
|
|||
private fun findElementInFile(psiFile: PsiFile?, editor: Editor): PsiElement? = psiFile?.findElementAt(editor.caretModel.offset) | |||
|
|||
private fun getClassFile(psiElement: PsiElement): ClassFile { | |||
val containingClass = ByteCodeViewerManager.getContainingClass(psiElement) ?: throw FileNotFoundException("<containing class>") | |||
val classVMName = getClassName(containingClass) ?: throw FileNotFoundException("<class name>") | |||
val module = ModuleUtilCore.findModuleForPsiElement(psiElement) | |||
return if (module == null) { | |||
getClassFileNoModule(psiElement, containingClass, classVMName) | |||
} else { | |||
getClassFileModule(module, containingClass, classVMName) | |||
} | |||
} | |||
|
|||
private fun getClassFileNoModule(psiElement: PsiElement, containingClass: PsiClass, classVMName: String): ClassFile { | |||
val project = containingClass.project | |||
val qualifiedName = PsiUtil.getTopLevelClass(psiElement)?.qualifiedName ?: throw FileNotFoundException("<top level class>") | |||
JavaPsiFacade.getInstance(project).findClass(qualifiedName, psiElement.resolveScope)?.let { psiClass -> | |||
val virtualFile = PsiUtilCore.getVirtualFile(psiClass) | |||
val fileIndex = ProjectRootManager.getInstance(project).fileIndex | |||
if (virtualFile != null && fileIndex.isInLibraryClasses(virtualFile)) { | |||
try { | |||
val rootForFile = fileIndex.getClassRootForFile(virtualFile) | |||
if (rootForFile != null) { | |||
val classFile = rootForFile.findFileByRelativePath("/" + classVMName.replace('.', '/') + ".class") | |||
if (classFile != null) { | |||
return readClassFile(classFile.inputStream) | |||
} | |||
} | |||
} catch (e: IOException) { | |||
LOG.error(e) | |||
} | |||
} | |||
} | |||
throw FileNotFoundException() | |||
} | |||
|
|||
private fun getClassFileModule(module: Module, containingClass: PsiClass, classVMName: String): ClassFile { | |||
val virtualFile = containingClass.containingFile.virtualFile ?: throw FileNotFoundException("<virtual file>") | |||
val moduleExtension = CompilerModuleExtension.getInstance(module) ?: throw FileNotFoundException("<module extension>") | |||
val file = File(if (ProjectRootManager.getInstance(module.project).fileIndex.isInTestSourceContent(virtualFile)) { | |||
val pathForTests = moduleExtension.compilerOutputPathForTests ?: throw FileNotFoundException("<compilerOutputPathForTests>") | |||
pathForTests.path | |||
} else { | |||
val compilerOutputPath = moduleExtension.compilerOutputPath ?: throw FileNotFoundException("<compilerOutputPath>") | |||
compilerOutputPath.path | |||
} + "/" + classVMName.replace('.', '/') + ".class") | |||
|
|||
if (file.exists()) { | |||
return readClassFile(file.inputStream()) | |||
} else { | |||
throw FileNotFoundException(file.path) | |||
} | |||
} | |||
|
|||
private fun readClassFile(inputStream: InputStream): ClassFile = ClassFileReader.readFromInputStream(inputStream) | |||
|
|||
private fun getClassName(containingClass: PsiClass): String? { | |||
if (containingClass is PsiAnonymousClass) { | |||
val containingClassOfAnonymous = PsiTreeUtil.getParentOfType(containingClass, PsiClass::class.java) ?: return null | |||
return getClassName(containingClassOfAnonymous) + JavaAnonymousClassesHelper.getName(containingClass) | |||
} else { | |||
return ClassUtil.getJVMClassName(containingClass) | |||
} | |||
} | |||
|
|||
companion object { | |||
private val ICON = IconLoader.getIcon("/icons/jclasslib.png") // 13x13 | |||
private val LOG = Logger.getInstance("#" + ShowBytecodeAction::class.java.name) | |||
} | |||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,17 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<!DOCTYPE idea-plugin PUBLIC "Plugin/DTD" "http://plugins.intellij.net/plugin.dtd"> | |||
<idea-plugin version="2" url="https://github.com/ingokegel/jclasslib"> | |||
<name>jclasslib</name> | |||
<description>Bytecode viewer jclasslib</description> | |||
<version>5.0</version> | |||
<idea-version since-build="162"/> | |||
|
|||
<depends>ByteCodeViewer</depends> | |||
|
|||
<actions> | |||
<action id="ShowByteCodeJclasslib" class="org.gjt.jclasslib.idea.ShowBytecodeAction" | |||
text="Show Bytecode With jclasslib"> | |||
<add-to-group group-id="QuickActions" anchor="after" relative-to-action="QuickJavaDoc"/> | |||
</action> | |||
</actions> | |||
</idea-plugin> |
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,25 @@ | |||
plugins { | |||
id 'org.jetbrains.intellij' version '0.1.10' | |||
} | |||
apply plugin: 'kotlin' | |||
|
|||
intellij { | |||
version 'IC-2016.2.5' | |||
pluginName 'jclasslib' | |||
} | |||
|
|||
sourceSets { | |||
main { | |||
kotlin { | |||
srcDirs += "../idea/src/main/kotlin" | |||
} | |||
resources { | |||
srcDirs += "../idea/src/main/resources" | |||
} | |||
} | |||
} | |||
|
|||
dependencies { | |||
compile project(':browser') | |||
compileOnly ':byteCodeViewer' | |||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters