├── .github └── FUNDING.yml ├── .gitignore ├── .idea ├── encodings.xml ├── misc.xml └── runConfigurations │ └── Plugin.xml ├── .run ├── [buildPlugin].run.xml ├── [publishPlugin].run.xml └── [runIde].run.xml ├── CHANGELOG.md ├── LICENSE.txt ├── README.md ├── VisualVMLauncher.iml ├── build.gradle.kts ├── gradle.properties ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── rasterize_icons.sh ├── settings.gradle.kts └── src └── main ├── java └── krasa │ └── visualvm │ ├── ApplicationSettingsService.java │ ├── Donate.java │ ├── Hacks.java │ ├── LogHelper.java │ ├── MyConfigurable.java │ ├── PluginSettings.java │ ├── Resources.java │ ├── SettingsDialog.form │ ├── SettingsDialog.java │ ├── action │ ├── FocusVisualVMAction.java │ ├── LauncherBasedAction.java │ ├── MyDumbAwareAction.java │ ├── StartVisualVMConsoleAction.java │ └── StartVisualVMMainToolbarAction.java │ ├── donate.gif │ ├── executor │ ├── DebugVisualVMExecutor.java │ └── RunVisualVMExecutor.java │ ├── integration │ ├── SourceRoots.java │ ├── VisualVMConsoleActionsPostProcessor.java │ ├── VisualVMContext.java │ ├── VisualVMHelper.java │ └── VisualVMJavaProgramPatcher.java │ └── runner │ ├── DebugVisualVMRunner.java │ ├── RunVisualVMRunner.java │ └── RunnerUtils.java └── resources ├── META-INF ├── plugin.xml └── pluginIcon.svg └── krasa └── visualvm ├── debug13.png ├── debug13@2x.png ├── debug13@2x_dark.png ├── debug13_dark.png ├── run13.png ├── run13@2x.png ├── run13@2x_dark.png ├── run13_dark.png └── svg ├── console16.svg ├── console16_dark.svg ├── debug16.svg ├── debug16_dark.svg ├── run16.svg └── run16_dark.svg /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [krasa] 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### java template 2 | .svn/ 3 | .idea/ 4 | .settings/ 5 | target/ 6 | out/ 7 | .classpath 8 | .project 9 | .mymetadata 10 | .DS_Store 11 | rebel.xml 12 | *.ipr 13 | *.iws 14 | VisualVMLauncher.jar 15 | 16 | .gradle 17 | .idea 18 | .qodana 19 | build 20 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/runConfigurations/Plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | -------------------------------------------------------------------------------- /.run/[buildPlugin].run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 16 | 18 | true 19 | true 20 | false 21 | false 22 | 23 | 24 | -------------------------------------------------------------------------------- /.run/[publishPlugin].run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 16 | 18 | true 19 | true 20 | false 21 | false 22 | 23 | 24 | -------------------------------------------------------------------------------- /.run/[runIde].run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 16 | 18 | true 19 | true 20 | false 21 | false 22 | 23 | 24 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [Unreleased] 4 | 5 | ## [1.23.0-IJ2023.3] - 2024-01-31 6 | - 2024.1 EAP compatibility 7 | 8 | ## [1.22.223] - 2023-08-01 9 | - IntelliJ 2023.2 compatibility 10 | 11 | ## [1.21.0] 12 | -
1.21 13 |
- IntelliJ 2022 compatibility 14 |
1.20 15 |
- NPE fix 16 |
1.19 17 |
- rebuild for JDK 1.8, small improvements 18 |
1.18 19 |
- added VisualVM process error dialog instead of the log file - can be disabled in settings 20 |
- added --laf option 21 |
- fixes 22 |
1.17 23 |
- support for GoToSource plugin v1.1 24 |
- bundled servers support fix 25 |
- process output log file in the IDE log folder 26 |
1.16 27 |
- fixes for GoToSource plugin 28 |
1.15 29 |
- support for VisualVM 2.0.4+ GoToSource plugin 30 |
1.14 31 |
- main toolbar action 32 |
1.13 33 |
- high resolution icons - thanks to Pei-Tang Huang 34 |
... 35 |
0.1 (2012-11-05) 36 |
- Initial release 37 | 38 | [Unreleased]: https://github.com/krasa/VisualVMLauncher/compare/v1.23.0-IJ2023.3...HEAD 39 | [1.23.0-IJ2023.3]: https://github.com/krasa/VisualVMLauncher/compare/v1.22.223...v1.23.0-IJ2023.3 40 | [1.22.223]: https://github.com/krasa/VisualVMLauncher/compare/v1.21.0...v1.22.223 41 | [1.21.0]: https://github.com/krasa/VisualVMLauncher/commits/v1.21.0 42 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VisualVMLauncher 2 | 3 | IntelliJ plugin - https://plugins.jetbrains.com/plugin/7115-visualvm-launcher/ 4 | 5 | --- 6 | -------------------------------------------------------------------------------- /VisualVMLauncher.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.changelog.Changelog 2 | 3 | fun properties(key: String) = providers.gradleProperty(key) 4 | fun environment(key: String) = providers.environmentVariable(key) 5 | 6 | tasks { 7 | buildSearchableOptions { 8 | enabled = false 9 | } 10 | compileJava { 11 | options.encoding = "UTF-8" 12 | } 13 | compileTestJava { 14 | options.encoding = "UTF-8" 15 | } 16 | } 17 | 18 | 19 | plugins { 20 | id("java") // Java support 21 | // alias(libs.plugins.kotlin) 22 | alias(libs.plugins.gradleIntelliJPlugin) // Gradle IntelliJ Plugin 23 | alias(libs.plugins.changelog) // Gradle Changelog Plugin 24 | // alias(libs.plugins.qodana) // Gradle Qodana Plugin 25 | // alias(libs.plugins.kover) // Gradle Kover Plugin 26 | } 27 | 28 | group = properties("pluginGroup").get() 29 | version = properties("pluginVersion").get() 30 | 31 | // Configure project's dependencies 32 | repositories { 33 | mavenCentral() 34 | } 35 | 36 | // Dependencies are managed with Gradle version catalog - read more: https://docs.gradle.org/current/userguide/platforms.html#sub:version-catalog 37 | 38 | dependencies { 39 | testImplementation(platform("org.junit:junit-bom:5.9.1")) 40 | testImplementation("org.junit.jupiter:junit-jupiter") 41 | } 42 | 43 | 44 | //// Set the JVM language level used to build the project. Use Java 11 for 2020.3+, and Java 17 for 2022.2+. 45 | //kotlin { 46 | // jvmToolchain(17) 47 | //} 48 | 49 | 50 | // Configure Gradle IntelliJ Plugin - read more: https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html 51 | intellij { 52 | pluginName = properties("pluginName") 53 | version = properties("platformVersion") 54 | type = properties("platformType") 55 | 56 | // Plugin Dependencies. Uses `platformPlugins` property from the gradle.properties file. 57 | plugins = properties("platformPlugins").map { it.split(',').map(String::trim).filter(String::isNotEmpty) } 58 | } 59 | 60 | // Configure Gradle Changelog Plugin - read more: https://github.com/JetBrains/gradle-changelog-plugin 61 | changelog { 62 | groups.empty() 63 | repositoryUrl = properties("pluginRepositoryUrl") 64 | } 65 | 66 | // Configure Gradle Qodana Plugin - read more: https://github.com/JetBrains/gradle-qodana-plugin 67 | //qodana { 68 | // cachePath = provider { file(".qodana").canonicalPath } 69 | // reportPath = provider { file("build/reports/inspections").canonicalPath } 70 | // saveReport = true 71 | // showReport = environment("QODANA_SHOW_REPORT").map { it.toBoolean() }.getOrElse(false) 72 | //} 73 | // 74 | //// Configure Gradle Kover Plugin - read more: https://github.com/Kotlin/kotlinx-kover#configuration 75 | //kover.xmlReport { 76 | // onCheck = true 77 | //} 78 | 79 | tasks { 80 | wrapper { 81 | gradleVersion = properties("gradleVersion").get() 82 | } 83 | 84 | patchPluginXml { 85 | version = properties("pluginVersion") 86 | sinceBuild = properties("pluginSinceBuild") 87 | untilBuild = properties("pluginUntilBuild") 88 | 89 | // // Extract the section from README.md and provide for the plugin's manifest 90 | // pluginDescription = providers.fileContents(layout.projectDirectory.file("README.md")).asText.map { 91 | // val start = "" 92 | // val end = "" 93 | // 94 | // with (it.lines()) { 95 | // if (!containsAll(listOf(start, end))) { 96 | // throw GradleException("Plugin description section not found in README.md:\n$start ... $end") 97 | // } 98 | // subList(indexOf(start) + 1, indexOf(end)).joinToString("\n").let(::markdownToHTML) 99 | // } 100 | // } 101 | 102 | val changelog = project.changelog // local variable for configuration cache compatibility 103 | // Get the latest available change notes from the changelog file 104 | changeNotes = properties("pluginVersion").map { pluginVersion -> 105 | with(changelog) { 106 | renderItem( 107 | (getOrNull(pluginVersion) ?: getUnreleased()) 108 | .withHeader(false) 109 | .withEmptySections(false), 110 | Changelog.OutputType.HTML, 111 | ) 112 | } 113 | } 114 | } 115 | 116 | // Configure UI tests plugin 117 | // Read more: https://github.com/JetBrains/intellij-ui-test-robot 118 | runIdeForUiTests { 119 | systemProperty("robot-server.port", "8082") 120 | systemProperty("ide.mac.message.dialogs.as.sheets", "false") 121 | systemProperty("jb.privacy.policy.text", "") 122 | systemProperty("jb.consents.confirmation.enabled", "false") 123 | } 124 | 125 | signPlugin { 126 | certificateChain = environment("CERTIFICATE_CHAIN") 127 | privateKey = environment("PRIVATE_KEY") 128 | password = environment("PRIVATE_KEY_PASSWORD") 129 | } 130 | 131 | publishPlugin { 132 | dependsOn("patchChangelog") 133 | token = environment("PUBLISH_TOKEN") 134 | // The pluginVersion is based on the SemVer (https://semver.org) and supports pre-release labels, like 2.1.7-alpha.3 135 | // Specify pre-release label to publish the plugin in a custom Release Channel automatically. Read more: 136 | // https://plugins.jetbrains.com/docs/intellij/deployment.html#specifying-a-release-channel 137 | // channels = properties("pluginVersion").map { listOf(it.split('-').getOrElse(1) { "default" }.split('.').first()) } 138 | } 139 | 140 | } 141 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # IntelliJ Platform Artifacts Repositories -> https://plugins.jetbrains.com/docs/intellij/intellij-artifacts.html 2 | 3 | pluginGroup=com.github.krasa.VisualVMLauncher 4 | pluginName=VisualVMLauncher 5 | pluginRepositoryUrl=https://github.com/krasa/VisualVMLauncher 6 | 7 | # SemVer format -> https://semver.org 8 | pluginVersion=1.23.0-IJ2023.3 9 | 10 | # Supported build number ranges and IntelliJ Platform versions -> https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html 11 | pluginSinceBuild=233 12 | pluginUntilBuild= 13 | 14 | # IntelliJ Platform Properties -> https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html#configuration-intellij-extension 15 | platformType=IC 16 | platformVersion=2023.3 17 | 18 | # Plugin Dependencies -> https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html 19 | # Example: platformPlugins = com.intellij.java, com.jetbrains.php:203.4449.22 20 | platformPlugins =com.intellij.java 21 | 22 | # Gradle Releases -> https://github.com/gradle/gradle/releases 23 | gradleVersion=8.5 24 | 25 | # Opt-out flag for bundling Kotlin standard library -> https://jb.gg/intellij-platform-kotlin-stdlib 26 | kotlin.stdlib.default.dependency = false 27 | 28 | # Enable Gradle Configuration Cache -> https://docs.gradle.org/current/userguide/configuration_cache.html 29 | org.gradle.configuration-cache = true 30 | 31 | # Enable Gradle Build Cache -> https://docs.gradle.org/current/userguide/build_cache.html 32 | org.gradle.caching=false 33 | 34 | # Enable Gradle Kotlin DSL Lazy Property Assignment -> https://docs.gradle.org/current/userguide/kotlin_dsl.html#kotdsl:assignment 35 | systemProp.org.gradle.unsafe.kotlin.assignment = true 36 | 37 | # Temporary workaround for Kotlin Compiler OutOfMemoryError -> https://jb.gg/intellij-platform-kotlin-oom 38 | kotlin.incremental.useClasspathSnapshot = false 39 | -------------------------------------------------------------------------------- /gradle/libs.versions.toml: -------------------------------------------------------------------------------- 1 | [versions] 2 | # libraries 3 | annotations = "24.0.1" 4 | 5 | # plugins 6 | kotlin = "1.9.0" 7 | changelog = "2.1.2" 8 | gradleIntelliJPlugin = "1.17.0" 9 | qodana = "0.1.13" 10 | kover = "0.7.2" 11 | 12 | [libraries] 13 | annotations = { group = "org.jetbrains", name = "annotations", version.ref = "annotations" } 14 | 15 | [plugins] 16 | changelog = { id = "org.jetbrains.changelog", version.ref = "changelog" } 17 | gradleIntelliJPlugin = { id = "org.jetbrains.intellij", version.ref = "gradleIntelliJPlugin" } 18 | kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } 19 | kover = { id = "org.jetbrains.kotlinx.kover", version.ref = "kover" } 20 | qodana = { id = "org.jetbrains.qodana", version.ref = "qodana" } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasa/VisualVMLauncher/5b97f289ee5a9cf2938e97ff5a6f37af6558c369/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip 4 | networkTimeout=10000 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | # This is normally unused 84 | # shellcheck disable=SC2034 85 | APP_BASE_NAME=${0##*/} 86 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 87 | 88 | # Use the maximum available, or set MAX_FD != -1 to use that value. 89 | MAX_FD=maximum 90 | 91 | warn () { 92 | echo "$*" 93 | } >&2 94 | 95 | die () { 96 | echo 97 | echo "$*" 98 | echo 99 | exit 1 100 | } >&2 101 | 102 | # OS specific support (must be 'true' or 'false'). 103 | cygwin=false 104 | msys=false 105 | darwin=false 106 | nonstop=false 107 | case "$( uname )" in #( 108 | CYGWIN* ) cygwin=true ;; #( 109 | Darwin* ) darwin=true ;; #( 110 | MSYS* | MINGW* ) msys=true ;; #( 111 | NONSTOP* ) nonstop=true ;; 112 | esac 113 | 114 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 115 | 116 | 117 | # Determine the Java command to use to start the JVM. 118 | if [ -n "$JAVA_HOME" ] ; then 119 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 120 | # IBM's JDK on AIX uses strange locations for the executables 121 | JAVACMD=$JAVA_HOME/jre/sh/java 122 | else 123 | JAVACMD=$JAVA_HOME/bin/java 124 | fi 125 | if [ ! -x "$JAVACMD" ] ; then 126 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 127 | 128 | Please set the JAVA_HOME variable in your environment to match the 129 | location of your Java installation." 130 | fi 131 | else 132 | JAVACMD=java 133 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 134 | 135 | Please set the JAVA_HOME variable in your environment to match the 136 | location of your Java installation." 137 | fi 138 | 139 | # Increase the maximum file descriptors if we can. 140 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 141 | case $MAX_FD in #( 142 | max*) 143 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 144 | # shellcheck disable=SC3045 145 | MAX_FD=$( ulimit -H -n ) || 146 | warn "Could not query maximum file descriptor limit" 147 | esac 148 | case $MAX_FD in #( 149 | '' | soft) :;; #( 150 | *) 151 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 152 | # shellcheck disable=SC3045 153 | ulimit -n "$MAX_FD" || 154 | warn "Could not set maximum file descriptor limit to $MAX_FD" 155 | esac 156 | fi 157 | 158 | # Collect all arguments for the java command, stacking in reverse order: 159 | # * args from the command line 160 | # * the main class name 161 | # * -classpath 162 | # * -D...appname settings 163 | # * --module-path (only if needed) 164 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 165 | 166 | # For Cygwin or MSYS, switch paths to Windows format before running java 167 | if "$cygwin" || "$msys" ; then 168 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 169 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 170 | 171 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 172 | 173 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 174 | for arg do 175 | if 176 | case $arg in #( 177 | -*) false ;; # don't mess with options #( 178 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 179 | [ -e "$t" ] ;; #( 180 | *) false ;; 181 | esac 182 | then 183 | arg=$( cygpath --path --ignore --mixed "$arg" ) 184 | fi 185 | # Roll the args list around exactly as many times as the number of 186 | # args, so each arg winds up back in the position where it started, but 187 | # possibly modified. 188 | # 189 | # NB: a `for` loop captures its iteration list before it begins, so 190 | # changing the positional parameters here affects neither the number of 191 | # iterations, nor the values presented in `arg`. 192 | shift # remove old arg 193 | set -- "$@" "$arg" # push replacement arg 194 | done 195 | fi 196 | 197 | 198 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 199 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 200 | 201 | # Collect all arguments for the java command; 202 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 203 | # shell script including quotes and variable substitutions, so put them in 204 | # double quotes to make sure that they get re-expanded; and 205 | # * put everything else in single quotes, so that it's not re-expanded. 206 | 207 | set -- \ 208 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 209 | -classpath "$CLASSPATH" \ 210 | org.gradle.wrapper.GradleWrapperMain \ 211 | "$@" 212 | 213 | # Stop when "xargs" is not available. 214 | if ! command -v xargs >/dev/null 2>&1 215 | then 216 | die "xargs is not available" 217 | fi 218 | 219 | # Use "xargs" to parse quoted args. 220 | # 221 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 222 | # 223 | # In Bash we could simply go: 224 | # 225 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 226 | # set -- "${ARGS[@]}" "$@" 227 | # 228 | # but POSIX shell has neither arrays nor command substitution, so instead we 229 | # post-process each arg (as a line of input to sed) to backslash-escape any 230 | # character that might be a shell metacharacter, then use eval to reverse 231 | # that process (while maintaining the separation between arguments), and wrap 232 | # the whole thing up as a single "set" statement. 233 | # 234 | # This will of course break if any of these variables contains a newline or 235 | # an unmatched quote. 236 | # 237 | 238 | eval "set -- $( 239 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 240 | xargs -n1 | 241 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 242 | tr '\n' ' ' 243 | )" '"$@"' 244 | 245 | exec "$JAVACMD" "$@" 246 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /rasterize_icons.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | inkscape -z -e resources/krasa/visualvm/debug13.png -w 13 -h 13 resources/krasa/visualvm/svg/debug16.svg 3 | inkscape -z -e resources/krasa/visualvm/debug13_dark.png -w 13 -h 13 resources/krasa/visualvm/svg/debug16_dark.svg 4 | inkscape -z -e resources/krasa/visualvm/debug13@2x.png -w 26 -h 26 resources/krasa/visualvm/svg/debug16.svg 5 | inkscape -z -e resources/krasa/visualvm/debug13@2x_dark.png -w 26 -h 26 resources/krasa/visualvm/svg/debug16_dark.svg 6 | 7 | inkscape -z -e resources/krasa/visualvm/run13.png -w 13 -h 13 resources/krasa/visualvm/svg/run16.svg 8 | inkscape -z -e resources/krasa/visualvm/run13_dark.png -w 13 -h 13 resources/krasa/visualvm/svg/run16_dark.svg 9 | inkscape -z -e resources/krasa/visualvm/run13@2x.png -w 26 -h 26 resources/krasa/visualvm/svg/run16.svg 10 | inkscape -z -e resources/krasa/visualvm/run13@2x_dark.png -w 26 -h 26 resources/krasa/visualvm/svg/run16_dark.svg 11 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "VisualVMLauncher" 2 | -------------------------------------------------------------------------------- /src/main/java/krasa/visualvm/ApplicationSettingsService.java: -------------------------------------------------------------------------------- 1 | package krasa.visualvm; 2 | 3 | import com.intellij.openapi.components.PersistentStateComponent; 4 | import com.intellij.openapi.components.ServiceManager; 5 | import com.intellij.openapi.components.State; 6 | import com.intellij.openapi.components.Storage; 7 | import com.intellij.openapi.diagnostic.Logger; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | @State(name = "VisualVMLauncher", storages = {@Storage("VisualVMLauncher.xml")}) 11 | public class ApplicationSettingsService implements PersistentStateComponent { 12 | private static final Logger log = Logger.getInstance(ApplicationSettingsService.class.getName()); 13 | 14 | private PluginSettings settings = new PluginSettings(); 15 | 16 | public static ApplicationSettingsService getInstance() { 17 | return ServiceManager.getService(ApplicationSettingsService.class); 18 | } 19 | 20 | @NotNull 21 | public String getComponentName() { 22 | return "VisualVMLauncher"; 23 | } 24 | 25 | 26 | @NotNull 27 | @Override 28 | public PluginSettings getState() { 29 | if (settings == null) { 30 | settings = new PluginSettings(); 31 | } 32 | return settings; 33 | } 34 | 35 | @Override 36 | public void loadState(PluginSettings state) { 37 | this.settings = state; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/krasa/visualvm/Donate.java: -------------------------------------------------------------------------------- 1 | package krasa.visualvm; 2 | 3 | import com.intellij.ide.BrowserUtil; 4 | import com.intellij.openapi.diagnostic.Logger; 5 | import com.intellij.openapi.util.IconLoader; 6 | 7 | import javax.swing.*; 8 | import java.awt.event.ActionEvent; 9 | import java.awt.event.ActionListener; 10 | 11 | public class Donate { 12 | private static final Logger LOG = Logger.getInstance(Donate.class); 13 | 14 | public static JComponent newDonateButton(JPanel donatePanel) { 15 | JButton donate = new JButton(); 16 | donate.setBorder(null); 17 | donate.setIcon(IconLoader.getIcon("donate.gif", Donate.class)); 18 | donate.setContentAreaFilled(false); 19 | donate.addActionListener(new ActionListener() { 20 | @Override 21 | public void actionPerformed(ActionEvent e) { 22 | BrowserUtil.browse("https://www.paypal.me/VojtechKrasa"); 23 | } 24 | }); 25 | donate.putClientProperty("JButton.backgroundColor", donatePanel.getBackground()); 26 | return donate; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/krasa/visualvm/Hacks.java: -------------------------------------------------------------------------------- 1 | package krasa.visualvm; 2 | 3 | /** 4 | * @author Vojtech Krasa 5 | */ 6 | public class Hacks { 7 | public static final String BUNDLED_SERVERS_RUN_PROFILE_STATE = "PatchedLocalState"; 8 | public static final String BUNDLED_SERVERS_RUN_PROFILE = "com.intellij.javaee"; 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/krasa/visualvm/LogHelper.java: -------------------------------------------------------------------------------- 1 | package krasa.visualvm; 2 | 3 | import com.intellij.openapi.diagnostic.Logger; 4 | 5 | public class LogHelper { 6 | private static final Logger log = Logger.getInstance(LogHelper.class.getName()); 7 | 8 | public static void print(String x, Object thisInstance) { 9 | if (log.isDebugEnabled()) { 10 | String simpleName = "LogHelper : "; 11 | if (thisInstance != null) { 12 | simpleName = thisInstance.getClass().getSimpleName() + ": "; 13 | } 14 | log.debug(simpleName + x); 15 | } 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/krasa/visualvm/MyConfigurable.java: -------------------------------------------------------------------------------- 1 | package krasa.visualvm; 2 | 3 | import com.intellij.openapi.options.Configurable; 4 | import com.intellij.openapi.options.ConfigurationException; 5 | import com.intellij.openapi.options.ShowSettingsUtil; 6 | import com.intellij.openapi.project.Project; 7 | import org.jetbrains.annotations.Nls; 8 | import org.jetbrains.annotations.NonNls; 9 | import org.jetbrains.annotations.Nullable; 10 | 11 | import javax.swing.*; 12 | 13 | public class MyConfigurable implements Configurable { 14 | private SettingsDialog form; 15 | 16 | public static boolean openSettingsIfNotConfigured(Project project) { 17 | ApplicationSettingsService instance = ApplicationSettingsService.getInstance(); 18 | PluginSettings state = instance.getState(); 19 | boolean ok = true; 20 | if (!PluginSettings.isValid(state)) { 21 | ok = ShowSettingsUtil.getInstance().editConfigurable(project, new MyConfigurable()); 22 | } 23 | return ok; 24 | } 25 | 26 | @Nls 27 | public String getDisplayName() { 28 | return "VisualVM Launcher"; 29 | } 30 | 31 | @Nullable 32 | public Icon getIcon() { 33 | return null; 34 | } 35 | 36 | @Nullable 37 | @NonNls 38 | public String getHelpTopic() { 39 | return null; 40 | } 41 | 42 | public JComponent createComponent() { 43 | if (form == null) { 44 | form = new SettingsDialog(); 45 | } 46 | return form.getRootComponent(); 47 | } 48 | 49 | public boolean isModified() { 50 | return form.isModified(ApplicationSettingsService.getInstance().getState()); 51 | } 52 | 53 | public void apply() throws ConfigurationException { 54 | PluginSettings settings = ApplicationSettingsService.getInstance().getState(); 55 | if (form != null) { 56 | form.getData(settings); 57 | } 58 | } 59 | 60 | public void reset() { 61 | PluginSettings settings = ApplicationSettingsService.getInstance().getState(); 62 | if (form != null) { 63 | form.setDataCustom(settings); 64 | } 65 | } 66 | 67 | public void disposeUIResources() { 68 | form = null; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/krasa/visualvm/PluginSettings.java: -------------------------------------------------------------------------------- 1 | package krasa.visualvm; 2 | 3 | import krasa.visualvm.integration.VisualVMHelper; 4 | 5 | public class PluginSettings { 6 | 7 | private String visualVmExecutable; 8 | private String durationToSetContextToButton = "10000"; 9 | private String delayForVisualVMStart = "10000"; 10 | private String jdkHome; 11 | private boolean useTabIndex; 12 | private String tabIndex = "2"; 13 | private boolean sourceConfig = false; 14 | private boolean useModuleJdk = true; 15 | private String laf = ""; 16 | 17 | 18 | public String getVisualVmExecutable() { 19 | return visualVmExecutable; 20 | } 21 | 22 | public void setVisualVmExecutable(final String visualVmExecutable) { 23 | this.visualVmExecutable = visualVmExecutable; 24 | } 25 | 26 | 27 | public static boolean isValid(PluginSettings state) { 28 | return state != null && VisualVMHelper.isValidPath(state.getVisualVmExecutable()); 29 | } 30 | 31 | public String getDurationToSetContextToButton() { 32 | return durationToSetContextToButton; 33 | } 34 | 35 | public void setDurationToSetContextToButton(final String durationToSetContextToButton) { 36 | this.durationToSetContextToButton = durationToSetContextToButton; 37 | } 38 | 39 | public String getDelayForVisualVMStart() { 40 | return delayForVisualVMStart; 41 | } 42 | 43 | public void setDelayForVisualVMStart(String delayForVisualVMStart) { 44 | this.delayForVisualVMStart = delayForVisualVMStart; 45 | } 46 | 47 | public long getDurationToSetContextToButtonAsLong() { 48 | return Long.parseLong(durationToSetContextToButton); 49 | } 50 | 51 | public long getDelayForVisualVMStartAsLong() { 52 | return Long.parseLong(delayForVisualVMStart); 53 | } 54 | 55 | 56 | public String getJdkHome() { 57 | return jdkHome; 58 | } 59 | 60 | public void setJdkHome(final String jdkHome) { 61 | this.jdkHome = jdkHome; 62 | } 63 | 64 | public boolean isUseTabIndex() { 65 | return useTabIndex; 66 | } 67 | 68 | public void setUseTabIndex(final boolean useTabIndex) { 69 | this.useTabIndex = useTabIndex; 70 | } 71 | 72 | public String getTabIndex() { 73 | return tabIndex; 74 | } 75 | 76 | public void setTabIndex(final String tabIndex) { 77 | this.tabIndex = tabIndex; 78 | } 79 | 80 | public boolean isSourceConfig() { 81 | return sourceConfig; 82 | } 83 | 84 | public void setSourceConfig(final boolean sourceConfig) { 85 | this.sourceConfig = sourceConfig; 86 | } 87 | 88 | public boolean isUseModuleJdk() { 89 | return useModuleJdk; 90 | } 91 | 92 | public void setUseModuleJdk(final boolean useModuleJdk) { 93 | this.useModuleJdk = useModuleJdk; 94 | } 95 | 96 | 97 | public String getLaf() { 98 | return laf; 99 | } 100 | 101 | public void setLaf(final String laf) { 102 | this.laf = laf; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/main/java/krasa/visualvm/Resources.java: -------------------------------------------------------------------------------- 1 | package krasa.visualvm; 2 | 3 | import com.intellij.openapi.util.IconLoader; 4 | 5 | import javax.swing.*; 6 | 7 | public class Resources { 8 | 9 | public static final Icon RUN_13 = IconLoader.getIcon("/krasa/visualvm/run13.png");//13 10 | public static final Icon DEBUG_13 = IconLoader.getIcon("/krasa/visualvm/debug13.png");//13 11 | 12 | public static final Icon RUN = IconLoader.getIcon("/krasa/visualvm/svg/run16.svg"); 13 | public static final Icon DEBUG = IconLoader.getIcon("/krasa/visualvm/svg/debug16.svg"); 14 | public static final Icon CONSOLE_RUN = IconLoader.getIcon("/krasa/visualvm/svg/console16.svg"); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/krasa/visualvm/SettingsDialog.form: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | -------------------------------------------------------------------------------- /src/main/java/krasa/visualvm/SettingsDialog.java: -------------------------------------------------------------------------------- 1 | package krasa.visualvm; 2 | 3 | import com.intellij.openapi.fileChooser.FileChooser; 4 | import com.intellij.openapi.fileChooser.FileChooserDescriptor; 5 | import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; 6 | import com.intellij.openapi.project.Project; 7 | import com.intellij.openapi.project.ProjectManager; 8 | import com.intellij.openapi.projectRoots.JavaSdk; 9 | import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil; 10 | import com.intellij.openapi.vfs.LocalFileSystem; 11 | import com.intellij.openapi.vfs.VirtualFile; 12 | import com.intellij.ui.components.labels.LinkLabel; 13 | import org.apache.commons.lang.StringUtils; 14 | import org.jetbrains.annotations.NotNull; 15 | 16 | import javax.swing.*; 17 | import javax.swing.event.DocumentEvent; 18 | import javax.swing.event.DocumentListener; 19 | import javax.swing.text.DefaultFormatterFactory; 20 | import javax.swing.text.NumberFormatter; 21 | import java.io.File; 22 | import java.text.NumberFormat; 23 | 24 | import static com.intellij.ide.BrowserUtil.browse; 25 | 26 | public class SettingsDialog { 27 | private JTextField visualVmExecutable; 28 | private JComponent rootComponent; 29 | private JButton browseButton; 30 | private JLabel validationMessageLabel; 31 | private JFormattedTextField duration; 32 | private JLabel durationLabel; 33 | private JFormattedTextField delayForStgartingVisualVM; 34 | private JTextField jdkHome; 35 | private JButton browseJdkHome; 36 | private JCheckBox openOnTabForCheckBox; 37 | private JTextField tabIndex; 38 | private JCheckBox sourceConfig; 39 | private LinkLabel linkLabel; 40 | private JPanel donatePanel; 41 | private JCheckBox useModuleJdk; 42 | private JTextField laf; 43 | private LinkLabel link; 44 | 45 | public SettingsDialog() { 46 | super(); 47 | donatePanel.add(Donate.newDonateButton(donatePanel)); 48 | link.setListener((LinkLabel linkLabel1, Object o) -> { 49 | browse(linkLabel1.getText()); 50 | }, null); 51 | duration.setFormatterFactory(getDefaultFormatterFactory()); 52 | delayForStgartingVisualVM.setFormatterFactory(getDefaultFormatterFactory()); 53 | 54 | 55 | browseButton.addActionListener(e -> browseForFile(visualVmExecutable)); 56 | browseJdkHome.addActionListener(e -> { 57 | JavaSdk instance = com.intellij.openapi.projectRoots.impl.JavaSdkImpl.getInstance(); 58 | 59 | String text = jdkHome.getText(); 60 | final VirtualFile toSelect = StringUtils.isBlank(text) ? SdkConfigurationUtil.getSuggestedSdkRoot(instance) : LocalFileSystem.getInstance().findFileByPath(text); 61 | 62 | Project defaultProject = ProjectManager.getInstance().getDefaultProject(); 63 | VirtualFile file = FileChooser.chooseFile(instance.getHomeChooserDescriptor(), defaultProject, toSelect); 64 | if (file != null) { 65 | jdkHome.setText(file.getPath()); 66 | } 67 | }); 68 | visualVmExecutable.getDocument().addDocumentListener(new DocumentListener() { 69 | 70 | @Override 71 | public void changedUpdate(DocumentEvent e) { 72 | updateLabel(e); 73 | } 74 | 75 | @Override 76 | public void insertUpdate(DocumentEvent e) { 77 | updateLabel(e); 78 | } 79 | 80 | @Override 81 | public void removeUpdate(DocumentEvent e) { 82 | updateLabel(e); 83 | } 84 | 85 | private void updateLabel(DocumentEvent e) { 86 | java.awt.EventQueue.invokeLater(new Runnable() { 87 | 88 | @Override 89 | public void run() { 90 | setValidationMessage(visualVmExecutable.getText()); 91 | } 92 | }); 93 | } 94 | }); 95 | 96 | linkLabel.setListener( 97 | (aSource, aLinkData) -> browse((String) aLinkData), 98 | "https://visualvm.github.io/sourcessupport.html"); 99 | } 100 | 101 | 102 | private DefaultFormatterFactory getDefaultFormatterFactory() { 103 | NumberFormatter defaultFormat = new NumberFormatter(); 104 | NumberFormat integerInstance = NumberFormat.getIntegerInstance(); 105 | integerInstance.setGroupingUsed(false); 106 | defaultFormat.setFormat(integerInstance 107 | ); 108 | return new DefaultFormatterFactory(defaultFormat); 109 | } 110 | 111 | private void browseForFile(@NotNull final JTextField target) { 112 | final FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor(); 113 | descriptor.setHideIgnored(true); 114 | 115 | descriptor.setTitle("Select VisualVM Executable"); 116 | String text = target.getText(); 117 | final VirtualFile toSelect = text == null || text.isEmpty() ? null 118 | : LocalFileSystem.getInstance().findFileByPath(text); 119 | 120 | // 10.5 does not have #chooseFile 121 | Project defaultProject = ProjectManager.getInstance().getDefaultProject(); 122 | VirtualFile[] virtualFile = FileChooser.chooseFiles(descriptor, defaultProject, toSelect); 123 | if (virtualFile != null && virtualFile.length > 0) { 124 | target.setText(virtualFile[0].getPath()); 125 | } 126 | } 127 | 128 | private void setValidationMessage(String visualVmExecutable1) { 129 | if (StringUtils.isBlank(visualVmExecutable1)) { 130 | validationMessageLabel.setText("Path is required"); 131 | } else if (!new File(visualVmExecutable1).exists()) { 132 | validationMessageLabel.setText("File does not exists"); 133 | } else { 134 | validationMessageLabel.setText(""); 135 | } 136 | } 137 | 138 | public JComponent getRootComponent() { 139 | return rootComponent; 140 | } 141 | 142 | public void setDataCustom(PluginSettings settings) { 143 | setData(settings); 144 | setValidationMessage(settings.getVisualVmExecutable()); 145 | } 146 | 147 | public void setData(PluginSettings data) { 148 | visualVmExecutable.setText(data.getVisualVmExecutable()); 149 | duration.setText(data.getDurationToSetContextToButton()); 150 | delayForStgartingVisualVM.setText(data.getDelayForVisualVMStart()); 151 | jdkHome.setText(data.getJdkHome()); 152 | openOnTabForCheckBox.setSelected(data.isUseTabIndex()); 153 | tabIndex.setText(data.getTabIndex()); 154 | sourceConfig.setSelected(data.isSourceConfig()); 155 | useModuleJdk.setSelected(data.isUseModuleJdk()); 156 | laf.setText(data.getLaf()); 157 | } 158 | 159 | public void getData(PluginSettings data) { 160 | data.setVisualVmExecutable(visualVmExecutable.getText()); 161 | data.setDurationToSetContextToButton(duration.getText()); 162 | data.setDelayForVisualVMStart(delayForStgartingVisualVM.getText()); 163 | data.setJdkHome(jdkHome.getText()); 164 | data.setUseTabIndex(openOnTabForCheckBox.isSelected()); 165 | data.setTabIndex(tabIndex.getText()); 166 | data.setSourceConfig(sourceConfig.isSelected()); 167 | data.setUseModuleJdk(useModuleJdk.isSelected()); 168 | data.setLaf(laf.getText()); 169 | } 170 | 171 | public boolean isModified(PluginSettings data) { 172 | if (visualVmExecutable.getText() != null ? !visualVmExecutable.getText().equals(data.getVisualVmExecutable()) : data.getVisualVmExecutable() != null) 173 | return true; 174 | if (duration.getText() != null ? !duration.getText().equals(data.getDurationToSetContextToButton()) : data.getDurationToSetContextToButton() != null) 175 | return true; 176 | if (delayForStgartingVisualVM.getText() != null ? !delayForStgartingVisualVM.getText().equals(data.getDelayForVisualVMStart()) : data.getDelayForVisualVMStart() != null) 177 | return true; 178 | if (jdkHome.getText() != null ? !jdkHome.getText().equals(data.getJdkHome()) : data.getJdkHome() != null) 179 | return true; 180 | if (openOnTabForCheckBox.isSelected() != data.isUseTabIndex()) return true; 181 | if (tabIndex.getText() != null ? !tabIndex.getText().equals(data.getTabIndex()) : data.getTabIndex() != null) 182 | return true; 183 | if (sourceConfig.isSelected() != data.isSourceConfig()) return true; 184 | if (useModuleJdk.isSelected() != data.isUseModuleJdk()) return true; 185 | if (laf.getText() != null ? !laf.getText().equals(data.getLaf()) : data.getLaf() != null) return true; 186 | return false; 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /src/main/java/krasa/visualvm/action/FocusVisualVMAction.java: -------------------------------------------------------------------------------- 1 | package krasa.visualvm.action; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import com.intellij.openapi.util.NlsActions; 5 | import krasa.visualvm.integration.VisualVMHelper; 6 | import org.jetbrains.annotations.Nullable; 7 | 8 | import javax.swing.*; 9 | 10 | public class FocusVisualVMAction extends MyDumbAwareAction { 11 | public FocusVisualVMAction() { 12 | } 13 | 14 | public FocusVisualVMAction(@Nullable @NlsActions.ActionText String text, @Nullable @NlsActions.ActionDescription String description, @Nullable Icon icon) { 15 | super(text, description, icon); 16 | } 17 | 18 | public void actionPerformed(AnActionEvent e) { 19 | VisualVMHelper.executeVisualVM(e.getProject(), "--window-to-front"); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/krasa/visualvm/action/LauncherBasedAction.java: -------------------------------------------------------------------------------- 1 | package krasa.visualvm.action; 2 | 3 | import com.intellij.execution.process.ProcessHandler; 4 | import com.intellij.execution.runners.ProcessProxyFactory; 5 | import com.intellij.openapi.actionSystem.AnActionEvent; 6 | import com.intellij.openapi.actionSystem.Presentation; 7 | 8 | import javax.swing.*; 9 | 10 | public abstract class LauncherBasedAction extends MyDumbAwareAction { 11 | protected final ProcessHandler myProcessHandler; 12 | 13 | LauncherBasedAction(String text, String description, Icon icon, ProcessHandler processHandler) { 14 | super(text, description, icon); 15 | myProcessHandler = processHandler; 16 | } 17 | 18 | @Override 19 | public void update(final AnActionEvent event) { 20 | final Presentation presentation = event.getPresentation(); 21 | if (!isVisible()) { 22 | presentation.setVisible(false); 23 | presentation.setEnabled(false); 24 | return; 25 | } 26 | presentation.setVisible(true); 27 | presentation.setEnabled(!myProcessHandler.isProcessTerminated()); 28 | } 29 | 30 | protected boolean isVisible() { 31 | return ProcessProxyFactory.getInstance().getAttachedProxy(myProcessHandler) != null; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/krasa/visualvm/action/MyDumbAwareAction.java: -------------------------------------------------------------------------------- 1 | package krasa.visualvm.action; 2 | 3 | import com.intellij.openapi.actionSystem.ActionUpdateThread; 4 | import com.intellij.openapi.project.DumbAwareAction; 5 | import com.intellij.openapi.util.NlsActions; 6 | import org.jetbrains.annotations.NotNull; 7 | import org.jetbrains.annotations.Nullable; 8 | 9 | import javax.swing.*; 10 | import java.util.function.Supplier; 11 | 12 | public abstract class MyDumbAwareAction extends DumbAwareAction { 13 | public MyDumbAwareAction() { 14 | } 15 | 16 | public MyDumbAwareAction(@Nullable Icon icon) { 17 | super(icon); 18 | } 19 | 20 | public MyDumbAwareAction(@Nullable @NlsActions.ActionText String text) { 21 | super(text); 22 | } 23 | 24 | public MyDumbAwareAction(@NotNull Supplier<@NlsActions.ActionText String> dynamicText) { 25 | super(dynamicText); 26 | } 27 | 28 | public MyDumbAwareAction(@Nullable @NlsActions.ActionText String text, @Nullable @NlsActions.ActionDescription String description, @Nullable Icon icon) { 29 | super(text, description, icon); 30 | } 31 | 32 | 33 | @Override 34 | public @NotNull ActionUpdateThread getActionUpdateThread() { 35 | return ActionUpdateThread.BGT; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/krasa/visualvm/action/StartVisualVMConsoleAction.java: -------------------------------------------------------------------------------- 1 | package krasa.visualvm.action; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import com.intellij.openapi.actionSystem.Presentation; 5 | import krasa.visualvm.ApplicationSettingsService; 6 | import krasa.visualvm.LogHelper; 7 | import krasa.visualvm.MyConfigurable; 8 | import krasa.visualvm.Resources; 9 | import krasa.visualvm.integration.VisualVMContext; 10 | import krasa.visualvm.integration.VisualVMHelper; 11 | 12 | import java.util.Iterator; 13 | import java.util.LinkedList; 14 | import java.util.List; 15 | 16 | public class StartVisualVMConsoleAction extends MyDumbAwareAction { 17 | private VisualVMContext visualVMContext; 18 | private boolean postConstructContextSet; 19 | private long created; 20 | 21 | public static volatile List currentlyExecuted = new LinkedList(); 22 | 23 | public StartVisualVMConsoleAction() { 24 | } 25 | 26 | public StartVisualVMConsoleAction(VisualVMContext visualVMContext) { 27 | super("Start VisualVM", null, Resources.CONSOLE_RUN); 28 | this.visualVMContext = visualVMContext; 29 | created = System.currentTimeMillis(); 30 | currentlyExecuted.add(this); 31 | LogHelper.print("created with " + visualVMContext, this); 32 | } 33 | 34 | @Override 35 | public void update(AnActionEvent e) { 36 | super.update(e); 37 | final Presentation presentation = e.getPresentation(); 38 | if (!VisualVMContext.isValid(visualVMContext)) { 39 | // presentation.setVisible(false); 40 | presentation.setEnabled(false); 41 | } else { 42 | presentation.setDescription("Open VisualVM with id=" + visualVMContext.getAppId()); 43 | } 44 | } 45 | 46 | @Override 47 | public void actionPerformed(final AnActionEvent e) { 48 | if (!MyConfigurable.openSettingsIfNotConfigured(e.getProject())) { 49 | return; 50 | } 51 | VisualVMHelper.startVisualVM(visualVMContext, e.getProject(), this); 52 | } 53 | 54 | public void setVisualVMContext(VisualVMContext visualVMContext) { 55 | if (postConstructContextSet) { 56 | LogHelper.print("setVisualVMContext false with " + visualVMContext, this); 57 | } else { 58 | postConstructContextSet = true; 59 | LogHelper.print("setVisualVMContext " + visualVMContext, this); 60 | this.visualVMContext = visualVMContext; 61 | } 62 | } 63 | 64 | public long getCreated() { 65 | return created; 66 | } 67 | 68 | public static void setVisualVMContextToRecentlyCreated(VisualVMContext visualVMContext) { 69 | LogHelper.print("#setVisualVMContextToRecentlyCreated" + visualVMContext, null); 70 | Iterator iterator = currentlyExecuted.iterator(); 71 | while (iterator.hasNext()) { 72 | StartVisualVMConsoleAction next = iterator.next(); 73 | if (isRecentlyCreated(next)) { 74 | next.setVisualVMContext(visualVMContext); 75 | } else { 76 | LogHelper.print("#setVisualVMContextToRecentlyCreated remove", null); 77 | iterator.remove(); 78 | } 79 | } 80 | } 81 | 82 | private static boolean isRecentlyCreated(StartVisualVMConsoleAction next) { 83 | long l = System.currentTimeMillis() - next.getCreated(); 84 | LogHelper.print("#isRecentlyCreated " + l + " " + next, null); 85 | return l < ApplicationSettingsService.getInstance().getState().getDurationToSetContextToButtonAsLong(); 86 | } 87 | 88 | @Override 89 | public String toString() { 90 | final StringBuilder sb = new StringBuilder(); 91 | sb.append("StartVisualVMConsoleAction"); 92 | sb.append("{visualVMContext=").append(visualVMContext); 93 | sb.append(", created=").append(created); 94 | sb.append('}'); 95 | return sb.toString(); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/krasa/visualvm/action/StartVisualVMMainToolbarAction.java: -------------------------------------------------------------------------------- 1 | package krasa.visualvm.action; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import com.intellij.openapi.actionSystem.DefaultActionGroup; 5 | import com.intellij.openapi.actionSystem.Separator; 6 | import com.intellij.openapi.fileChooser.FileChooser; 7 | import com.intellij.openapi.fileChooser.FileChooserDescriptor; 8 | import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; 9 | import com.intellij.openapi.project.DumbAwareAction; 10 | import com.intellij.openapi.project.Project; 11 | import com.intellij.openapi.project.ProjectManager; 12 | import com.intellij.openapi.projectRoots.JavaSdk; 13 | import com.intellij.openapi.projectRoots.ProjectJdkTable; 14 | import com.intellij.openapi.projectRoots.Sdk; 15 | import com.intellij.openapi.ui.popup.JBPopupFactory; 16 | import com.intellij.openapi.ui.popup.ListPopup; 17 | import com.intellij.openapi.vfs.VirtualFile; 18 | import krasa.visualvm.ApplicationSettingsService; 19 | import krasa.visualvm.PluginSettings; 20 | import krasa.visualvm.integration.VisualVMHelper; 21 | import org.apache.commons.lang.StringUtils; 22 | import org.jetbrains.annotations.NotNull; 23 | 24 | import java.awt.event.InputEvent; 25 | import java.util.HashSet; 26 | import java.util.Set; 27 | 28 | public class StartVisualVMMainToolbarAction extends MyDumbAwareAction { 29 | 30 | public void actionPerformed(AnActionEvent e) { 31 | boolean ok = checkVisualVmExecutable(); 32 | if (!ok) { 33 | return; 34 | } 35 | 36 | DefaultActionGroup defaultActionGroup = new DefaultActionGroup(); 37 | defaultActionGroup.add(new MyDumbAwareAction("No JDK (system default)", null)); 38 | // defaultActionGroup.add(new FocusVisualVMAction("Focus VisualVM", null, null)); 39 | defaultActionGroup.add(new Separator()); 40 | 41 | Set homes = jdkHomes(); 42 | 43 | homes.stream().sorted().forEach(o -> defaultActionGroup.add(new MyDumbAwareAction(o, o))); 44 | 45 | ListPopup popup = JBPopupFactory.getInstance().createActionGroupPopup("Select JDK for --jdkhome VisualVM parameter", defaultActionGroup, e.getDataContext(), JBPopupFactory.ActionSelectionAid.ALPHA_NUMBERING, true, (Runnable) null, -1); 46 | InputEvent inputEvent = e.getInputEvent(); 47 | if (inputEvent != null) { 48 | popup.showInCenterOf(inputEvent.getComponent()); 49 | } else { 50 | popup.showInBestPositionFor(e.getDataContext()); 51 | 52 | } 53 | } 54 | 55 | @NotNull 56 | private Set jdkHomes() { 57 | Set homes = new HashSet<>(); 58 | 59 | PluginSettings state = ApplicationSettingsService.getInstance().getState(); 60 | String configuredJdkHome = state.getJdkHome(); 61 | if (StringUtils.isNotBlank(configuredJdkHome)) { 62 | homes.add(configuredJdkHome); 63 | } 64 | 65 | ProjectJdkTable projectJdkTable = ProjectJdkTable.getInstance(); 66 | JavaSdk javaSdk = JavaSdk.getInstance(); 67 | for (Sdk sdk : projectJdkTable.getAllJdks()) { 68 | if (sdk.getSdkType() == javaSdk) { 69 | homes.add(sdk.getHomePath()); 70 | } 71 | } 72 | return homes; 73 | } 74 | 75 | private boolean checkVisualVmExecutable() { 76 | PluginSettings state = ApplicationSettingsService.getInstance().getState(); 77 | String visualVmPath = state.getVisualVmExecutable(); 78 | if (org.apache.commons.lang.StringUtils.isBlank(visualVmPath)) { 79 | final FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor(); 80 | descriptor.setHideIgnored(true); 81 | 82 | descriptor.setTitle("Select VisualVM Executable"); 83 | Project defaultProject = ProjectManager.getInstance().getDefaultProject(); 84 | VirtualFile virtualFile = FileChooser.chooseFile(descriptor, defaultProject, null); 85 | if (virtualFile != null) { 86 | String path = virtualFile.getPath(); 87 | state.setVisualVmExecutable(path); 88 | } else { 89 | return false; 90 | } 91 | } 92 | return true; 93 | } 94 | 95 | 96 | private static class MyDumbAwareAction extends DumbAwareAction { 97 | private final String homePath; 98 | 99 | public MyDumbAwareAction(String name, String homePath) { 100 | super(name); 101 | this.homePath = homePath; 102 | } 103 | 104 | @Override 105 | public void actionPerformed(@NotNull AnActionEvent anActionEvent) { 106 | VisualVMHelper.startVisualVM(anActionEvent.getProject(), homePath); 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/main/java/krasa/visualvm/donate.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasa/VisualVMLauncher/5b97f289ee5a9cf2938e97ff5a6f37af6558c369/src/main/java/krasa/visualvm/donate.gif -------------------------------------------------------------------------------- /src/main/java/krasa/visualvm/executor/DebugVisualVMExecutor.java: -------------------------------------------------------------------------------- 1 | package krasa.visualvm.executor; 2 | 3 | import javax.swing.*; 4 | 5 | import krasa.visualvm.Resources; 6 | 7 | import org.jetbrains.annotations.NonNls; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | import com.intellij.execution.executors.DefaultRunExecutor; 11 | 12 | public class DebugVisualVMExecutor extends DefaultRunExecutor { 13 | @NonNls 14 | public static final String EXECUTOR_ID = "Debug with VisualVM"; 15 | public static final String DEBUG_WITH_VISUAL_VM = "DebugWithVisualVM"; 16 | 17 | @NotNull 18 | public String getToolWindowId() { 19 | return getId(); 20 | } 21 | 22 | public Icon getToolWindowIcon() { 23 | return Resources.DEBUG_13; 24 | } 25 | 26 | @NotNull 27 | public Icon getIcon() { 28 | return Resources.DEBUG; 29 | } 30 | 31 | public Icon getDisabledIcon() { 32 | return null; 33 | } 34 | 35 | public String getDescription() { 36 | return EXECUTOR_ID; 37 | } 38 | 39 | @NotNull 40 | public String getActionName() { 41 | return DEBUG_WITH_VISUAL_VM; 42 | } 43 | 44 | @NotNull 45 | public String getId() { 46 | return EXECUTOR_ID; 47 | } 48 | 49 | @NotNull 50 | public String getStartActionText() { 51 | return EXECUTOR_ID; 52 | } 53 | 54 | public String getContextActionId() { 55 | // HACK: ExecutorRegistryImpl expects this to be non-null, but we don't want any context actions for every file 56 | return getId() + " context-action-does-not-exist"; 57 | } 58 | 59 | public String getHelpId() { 60 | return null; 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/krasa/visualvm/executor/RunVisualVMExecutor.java: -------------------------------------------------------------------------------- 1 | package krasa.visualvm.executor; 2 | 3 | import javax.swing.*; 4 | 5 | import krasa.visualvm.Resources; 6 | 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | import com.intellij.execution.executors.DefaultRunExecutor; 10 | 11 | public class RunVisualVMExecutor extends DefaultRunExecutor { 12 | 13 | public static final String RUN_WITH_VISUAL_VM = "Run with VisualVM"; 14 | public static final String RUN_WITH_VISUAL_VM1 = "RunWithVisualVM"; 15 | 16 | @NotNull 17 | public String getToolWindowId() { 18 | return getId(); 19 | } 20 | 21 | public Icon getToolWindowIcon() { 22 | return Resources.RUN_13; 23 | } 24 | 25 | @NotNull 26 | public Icon getIcon() { 27 | return Resources.RUN; 28 | } 29 | 30 | public Icon getDisabledIcon() { 31 | return null; 32 | } 33 | 34 | public String getDescription() { 35 | return RUN_WITH_VISUAL_VM; 36 | } 37 | 38 | @NotNull 39 | public String getActionName() { 40 | return RUN_WITH_VISUAL_VM1; 41 | } 42 | 43 | @NotNull 44 | public String getId() { 45 | return RUN_WITH_VISUAL_VM; 46 | } 47 | 48 | @NotNull 49 | public String getStartActionText() { 50 | return RUN_WITH_VISUAL_VM; 51 | } 52 | 53 | public String getContextActionId() { 54 | // HACK: ExecutorRegistryImpl expects this to be non-null, but we don't want any context actions for every file 55 | return getId() + " context-action-does-not-exist"; 56 | } 57 | 58 | public String getHelpId() { 59 | return null; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/krasa/visualvm/integration/SourceRoots.java: -------------------------------------------------------------------------------- 1 | package krasa.visualvm.integration; 2 | 3 | import com.intellij.openapi.module.Module; 4 | import com.intellij.openapi.module.ModuleManager; 5 | import com.intellij.openapi.project.Project; 6 | import com.intellij.openapi.roots.*; 7 | import com.intellij.openapi.util.SystemInfo; 8 | import com.intellij.openapi.util.text.StringUtil; 9 | import com.intellij.openapi.vfs.VfsUtilCore; 10 | import com.intellij.openapi.vfs.VirtualFile; 11 | import com.intellij.util.containers.MultiMap; 12 | import org.jetbrains.annotations.NotNull; 13 | import org.jetbrains.jps.model.module.JpsModuleSourceRootType; 14 | 15 | import java.io.File; 16 | import java.util.*; 17 | 18 | public class SourceRoots { 19 | 20 | @NotNull 21 | static String resolve(Project project, Module runConfigurationModule) { 22 | //https://visualvm.github.io/sourcessupport.html 23 | // --source-roots="c:\sources\root1;c:\sources\root2[subpaths=src:test\src]" 24 | 25 | SourceRoots sourceRoots = new SourceRoots(); 26 | 27 | if (runConfigurationModule != null) { 28 | sourceRoots.addModuleDependencies(runConfigurationModule); 29 | } else { 30 | ModuleManager manager = ModuleManager.getInstance(project); 31 | Module[] modules = manager.getModules(); 32 | for (Module module : modules) { 33 | sourceRoots.addModuleDependencies(module); 34 | } 35 | } 36 | 37 | return sourceRoots.getVisualVmParameter(); 38 | } 39 | 40 | 41 | private MultiMap jarsWithSubpaths = new MultiMap<>(); 42 | private Set jars = new HashSet<>(); 43 | private Set moduleContentRoots = new HashSet<>(); 44 | 45 | private Set cycleProtection = new HashSet<>(); 46 | 47 | private void addModuleDependencies(Module module) { 48 | if (cycleProtection.contains(module)) { 49 | return; 50 | } else { 51 | cycleProtection.add(module); 52 | } 53 | 54 | ModuleRootManager root = ModuleRootManager.getInstance(module); 55 | OrderEntry[] orderEntries = root.getOrderEntries(); 56 | for (OrderEntry orderEntry : orderEntries) { 57 | if (orderEntry instanceof ModuleOrderEntry) { 58 | Module moduleDep = ((ModuleOrderEntry) orderEntry).getModule(); 59 | addModule(moduleDep); 60 | addModuleDependencies(moduleDep); 61 | } else if (orderEntry instanceof ModuleSourceOrderEntry) { 62 | Module module1 = ((ModuleSourceOrderEntry) orderEntry).getRootModel().getModule(); 63 | addModule(module1); 64 | } else { 65 | // if (orderEntry instanceof LibraryOrderEntry || orderEntry instanceof InheritedJdkOrderEntry) { 66 | // 67 | // } else { 68 | // System.err.println(); 69 | // } 70 | VirtualFile[] sources = orderEntry.getFiles(OrderRootType.SOURCES); 71 | for (VirtualFile virtualFile : sources) { 72 | add(virtualFile); 73 | } 74 | } 75 | 76 | } 77 | } 78 | 79 | public void add(VirtualFile root) { 80 | String path = root.getPath(); 81 | if (path.contains("!/")) { 82 | String jar = StringUtil.substringBefore(path, "!/"); 83 | String subpath = StringUtil.substringAfter(path, "!/"); 84 | jarsWithSubpaths.putValue(jar, subpath); 85 | } else { 86 | jars.add(path); 87 | } 88 | } 89 | 90 | public void addModule(Module module) { 91 | ModuleRootManager root = ModuleRootManager.getInstance(module); 92 | ContentEntry[] contentEntries = root.getContentEntries(); 93 | for (ContentEntry contentEntry : contentEntries) { 94 | moduleContentRoots.add(new ModuleContentRoots(contentEntry)); 95 | } 96 | } 97 | 98 | public String getVisualVmParameter() { 99 | StringBuilder sb = new StringBuilder(); 100 | for (ModuleContentRoots sourceRoot : moduleContentRoots) { 101 | sourceRoot.appendTo(sb); 102 | } 103 | 104 | for (String jar : jars) { 105 | sb.append(jar); 106 | sb.append(File.pathSeparator); 107 | } 108 | 109 | for (Map.Entry> stringCollectionEntry : jarsWithSubpaths.entrySet()) { 110 | String key = stringCollectionEntry.getKey(); 111 | Collection value = stringCollectionEntry.getValue(); 112 | appendTo(sb, key, new HashSet<>(value)); 113 | } 114 | 115 | 116 | String sourceRootsText = removeLastSeparator(sb.toString()); 117 | if (SystemInfo.isWindows) { 118 | sourceRootsText = sourceRootsText.replace("/", "\\"); 119 | } 120 | return sourceRootsText; 121 | } 122 | 123 | 124 | private void appendTo(StringBuilder sb, String key, Set subpaths) { 125 | subpaths.remove(""); 126 | 127 | if (subpaths.isEmpty()) { 128 | sb.append(key); 129 | } else { 130 | sb.append(key); 131 | 132 | sb.append("[subpaths="); 133 | for (String s : subpaths) { 134 | sb.append(s); 135 | sb.append(":"); 136 | } 137 | removeLastSeparator(sb, ":"); 138 | sb.append("]"); 139 | } 140 | sb.append(File.pathSeparator); 141 | } 142 | 143 | 144 | @Override 145 | public String toString() { 146 | StringBuilder sb = new StringBuilder("Dependencies{" + 147 | "map=\n"); 148 | 149 | sb.append("\nsourceRoot="); 150 | for (ModuleContentRoots sourceRoot : moduleContentRoots) { 151 | sb.append("\n\t-"); 152 | sourceRoot.appendTo(sb); 153 | } 154 | 155 | for (Map.Entry> stringCollectionEntry : jarsWithSubpaths.entrySet()) { 156 | sb.append("\n") 157 | .append(stringCollectionEntry.getKey()); 158 | Collection value = stringCollectionEntry.getValue(); 159 | HashSet strings = new HashSet<>(value); 160 | strings.remove(""); 161 | for (String s : strings) { 162 | sb.append("\n\t-").append(s); 163 | } 164 | } 165 | sb.append("\njars="); 166 | for (String jar : jars) { 167 | sb.append("\n\t-").append(jar); 168 | } 169 | 170 | return sb.toString(); 171 | } 172 | 173 | private static class ModuleContentRoots { 174 | private final ContentEntry contentEntry; 175 | private final VirtualFile contentEntryFile; 176 | private final List paths = new ArrayList<>(); 177 | 178 | public ModuleContentRoots(ContentEntry contentEntry) { 179 | this.contentEntry = contentEntry; 180 | contentEntryFile = contentEntry.getFile(); 181 | 182 | SourceFolder[] sourceFolders = contentEntry.getSourceFolders(); 183 | for (SourceFolder sourceFolder : sourceFolders) { 184 | JpsModuleSourceRootType rootType = sourceFolder.getRootType(); 185 | if (rootType.getClass().getName().contains("ResourceRootType")) { 186 | continue; 187 | } 188 | VirtualFile file = sourceFolder.getFile(); 189 | if (file != null) { 190 | paths.add(file); 191 | } 192 | } 193 | } 194 | 195 | public void appendTo(StringBuilder sb) { 196 | if (paths.isEmpty()) { 197 | return; 198 | } else if (paths.size() == 1) { 199 | sb.append(paths.get(0).getPath()); 200 | } else { 201 | sb.append(contentEntryFile.getPath()); 202 | sb.append("[subpaths="); 203 | for (VirtualFile file : paths) { 204 | sb.append(VfsUtilCore.getRelativePath(file, contentEntryFile)); 205 | sb.append(":"); 206 | } 207 | removeLastSeparator(sb, ":"); 208 | sb.append("]"); 209 | } 210 | sb.append(File.pathSeparator); 211 | } 212 | 213 | @Override 214 | public boolean equals(Object o) { 215 | if (this == o) return true; 216 | if (o == null || getClass() != o.getClass()) return false; 217 | 218 | ModuleContentRoots that = (ModuleContentRoots) o; 219 | 220 | return contentEntry != null ? contentEntry.equals(that.contentEntry) : that.contentEntry == null; 221 | } 222 | 223 | @Override 224 | public int hashCode() { 225 | return contentEntry != null ? contentEntry.hashCode() : 0; 226 | } 227 | } 228 | 229 | private static String removeLastSeparator(String toString) { 230 | if (toString.endsWith(File.pathSeparator)) { 231 | return toString.substring(0, toString.length() - 1); 232 | } 233 | return toString; 234 | } 235 | 236 | private static void removeLastSeparator(StringBuilder sb, String suffix) { 237 | if (sb.substring(sb.length() - 1).equals(suffix)) { 238 | sb.setLength(sb.length() - 1); 239 | } 240 | } 241 | 242 | } 243 | -------------------------------------------------------------------------------- /src/main/java/krasa/visualvm/integration/VisualVMConsoleActionsPostProcessor.java: -------------------------------------------------------------------------------- 1 | package krasa.visualvm.integration; 2 | 3 | import com.intellij.execution.actions.ConsoleActionsPostProcessor; 4 | import com.intellij.execution.ui.ConsoleView; 5 | import com.intellij.openapi.actionSystem.AnAction; 6 | import com.intellij.openapi.diagnostic.Logger; 7 | import krasa.visualvm.action.StartVisualVMConsoleAction; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | import java.util.ArrayList; 11 | import java.util.Arrays; 12 | 13 | public class VisualVMConsoleActionsPostProcessor extends ConsoleActionsPostProcessor { 14 | private static final Logger log = Logger.getInstance(VisualVMConsoleActionsPostProcessor.class.getName()); 15 | 16 | @NotNull 17 | @Override 18 | public AnAction[] postProcess(@NotNull ConsoleView console, @NotNull AnAction[] actions) { 19 | VisualVMContext context = VisualVMContext.load(); 20 | ArrayList anActions = new ArrayList(); 21 | anActions.add(new StartVisualVMConsoleAction(context)); 22 | anActions.addAll(Arrays.asList(actions)); 23 | return anActions.toArray(new AnAction[anActions.size()]); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/krasa/visualvm/integration/VisualVMContext.java: -------------------------------------------------------------------------------- 1 | package krasa.visualvm.integration; 2 | 3 | import com.intellij.openapi.diagnostic.Logger; 4 | import com.intellij.openapi.module.Module; 5 | 6 | /*dirty, but works*/ 7 | public class VisualVMContext { 8 | private static final Logger log = Logger.getInstance(VisualVMContext.class.getName()); 9 | private static volatile VisualVMContext currentlyExecuted; 10 | 11 | protected Long appId; 12 | protected Module module; 13 | protected String jdkPath; 14 | 15 | public VisualVMContext(Long appId, String jdkPath, Module module) { 16 | this.appId = appId; 17 | this.jdkPath = jdkPath; 18 | this.module = module; 19 | } 20 | 21 | public Long getAppId() { 22 | return appId; 23 | } 24 | 25 | public String getJdkPath() { 26 | return jdkPath; 27 | } 28 | 29 | public void save() { 30 | if (log.isDebugEnabled()) { 31 | log.debug("saving context: " + this.toString()); 32 | } 33 | VisualVMContext.currentlyExecuted = this; 34 | } 35 | 36 | public static VisualVMContext load() { 37 | return currentlyExecuted; 38 | } 39 | 40 | public static boolean isValid(VisualVMContext visualVMContext) { 41 | return visualVMContext != null && visualVMContext.getAppId() != null; 42 | } 43 | 44 | public Module getModule() { 45 | return module; 46 | } 47 | 48 | public void setModule(Module module) { 49 | this.module = module; 50 | } 51 | 52 | @Override 53 | public String toString() { 54 | final StringBuilder sb = new StringBuilder(); 55 | sb.append("VisualVMContext"); 56 | sb.append("{appId=").append(appId); 57 | sb.append(", module='").append(module).append('\''); 58 | // sb.append(", jdkPath='").append(jdkPath).append('\''); 59 | sb.append('}'); 60 | return sb.toString(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/krasa/visualvm/integration/VisualVMHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 | * 5 | * This code is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License version 2 only, as 7 | * published by the Free Software Foundation. Oracle designates this 8 | * particular file as subject to the "Classpath" exception as provided 9 | * by Oracle in the LICENSE file that accompanied this code. 10 | * 11 | * This code is distributed in the hope that it will be useful, but WITHOUT 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 | * version 2 for more details (a copy is included in the LICENSE file that 15 | * accompanied this code). 16 | * 17 | * You should have received a copy of the GNU General Public License version 18 | * 2 along with this work; if not, write to the Free Software Foundation, 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 | * 21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 | * or visit www.oracle.com if you need additional information or have any 23 | * questions. 24 | */ 25 | package krasa.visualvm.integration; 26 | 27 | import com.intellij.notification.*; 28 | import com.intellij.openapi.application.ApplicationManager; 29 | import com.intellij.openapi.application.ApplicationNamesInfo; 30 | import com.intellij.openapi.application.PathManager; 31 | import com.intellij.openapi.diagnostic.Logger; 32 | import com.intellij.openapi.module.Module; 33 | import com.intellij.openapi.project.Project; 34 | import com.intellij.openapi.util.SystemInfo; 35 | import com.intellij.openapi.util.io.FileUtil; 36 | import com.intellij.util.system.CpuArch; 37 | import krasa.visualvm.ApplicationSettingsService; 38 | import krasa.visualvm.LogHelper; 39 | import krasa.visualvm.PluginSettings; 40 | import org.apache.commons.lang.StringUtils; 41 | import org.jetbrains.annotations.NotNull; 42 | 43 | import java.io.File; 44 | import java.io.FileOutputStream; 45 | import java.io.IOException; 46 | import java.io.OutputStreamWriter; 47 | import java.util.ArrayList; 48 | import java.util.Arrays; 49 | import java.util.List; 50 | import java.util.Properties; 51 | 52 | public final class VisualVMHelper { 53 | private static final Logger log = Logger.getInstance(VisualVMHelper.class.getName()); 54 | 55 | public static void startVisualVM(VisualVMContext vmContext, Project project, Object thisInstance) { 56 | if (vmContext == null) { 57 | log.warn("VisualVMContext is null"); 58 | return; 59 | } 60 | VisualVMHelper.openInVisualVM(vmContext.getAppId(), vmContext.getJdkPath(), vmContext.getModule(), project, thisInstance); 61 | } 62 | 63 | public static long getNextID() { 64 | return System.nanoTime(); 65 | } 66 | 67 | public static void startVisualVM(Project project, String jdkHome_doNotOverride) { 68 | PluginSettings state = ApplicationSettingsService.getInstance().getState(); 69 | 70 | String visualVmPath = state.getVisualVmExecutable(); 71 | if (!isValidPath(visualVmPath)) { 72 | NotificationGroup group = NotificationGroupManager.getInstance().getNotificationGroup("VisualVMLauncher"); 73 | Notification notification = group.createNotification("Path to VisualVM is not valid, path='" + visualVmPath + "'", NotificationType.ERROR); 74 | ApplicationManager.getApplication().invokeLater(() -> Notifications.Bus.notify(notification)); 75 | } else { 76 | try { 77 | if (StringUtils.isBlank(jdkHome_doNotOverride)) { 78 | new VisualVMProcess(project, visualVmPath).run(); 79 | } else { 80 | new VisualVMProcess(project, visualVmPath, "--jdkhome", jdkHome_doNotOverride).run(); 81 | } 82 | } catch (IOException e) { 83 | throw new RuntimeException("visualVmPath=" + visualVmPath + "; jdkHome=" + jdkHome_doNotOverride, e); 84 | } 85 | } 86 | 87 | } 88 | 89 | public static void openInVisualVM(long id, String jdkHome, Module module, Project project, Object thisInstance) { 90 | PluginSettings pluginSettings = ApplicationSettingsService.getInstance().getState(); 91 | 92 | String visualVmPath = pluginSettings.getVisualVmExecutable(); 93 | String customJdkHome = pluginSettings.getJdkHome(); 94 | boolean useModuleJdk = pluginSettings.isUseModuleJdk(); 95 | boolean sourceConfig = pluginSettings.isSourceConfig(); 96 | 97 | if (useModuleJdk) { 98 | if (StringUtils.isBlank(jdkHome)) { 99 | jdkHome = customJdkHome; 100 | } 101 | } else { 102 | jdkHome = customJdkHome; 103 | } 104 | 105 | String idString = String.valueOf(id); 106 | if (pluginSettings.isUseTabIndex()) { 107 | idString += "@" + pluginSettings.getTabIndex(); 108 | } 109 | 110 | if (!isValidPath(visualVmPath)) { 111 | NotificationGroup group = NotificationGroupManager.getInstance().getNotificationGroup("VisualVMLauncher"); 112 | Notification myNotification = group.createNotification("Path to VisualVM is not valid, path='" + visualVmPath + "'", NotificationType.ERROR); 113 | ApplicationManager.getApplication().invokeLater(() -> Notifications.Bus.notify(myNotification)); 114 | } else { 115 | run(jdkHome, project, visualVmPath, idString, sourceConfig, module, thisInstance); 116 | } 117 | } 118 | 119 | private static void run(String jdkHome, Project project, String visualVmPath, String idString, boolean sourceConfig, Module module, Object thisInstance) { 120 | LogHelper.print("starting VisualVM with id=" + idString, thisInstance); 121 | List cmds = new ArrayList<>(); 122 | try { 123 | cmds.add(visualVmPath); 124 | if (!StringUtils.isBlank(jdkHome)) { 125 | cmds.add("--jdkhome"); 126 | cmds.add(jdkHome); 127 | } 128 | cmds.add("--openid"); 129 | cmds.add(idString); 130 | if (sourceConfig) { 131 | try { 132 | cmds.add("--source-config"); 133 | cmds.add(createSourceConfig(project, module).getAbsolutePath()); 134 | } catch (Throwable e) { 135 | log.error(e); 136 | } 137 | } 138 | new VisualVMProcess(project, cmds.toArray(new String[0])).run(); 139 | } catch (IOException e) { 140 | if (sourceConfig) { 141 | boolean contains = e.getMessage().contains("The filename or extension is too long"); 142 | if (contains) { 143 | log.error("Please disable 'Integrate with VisualVM-GoToSource plugin' option at 'File | Settings | Other Settings | VisualVM Launcher'.\nThe command was too long: " + cmds.toString().length(), e); 144 | run(jdkHome, project, visualVmPath, idString, false, module, thisInstance); 145 | return; 146 | } 147 | } 148 | throw new RuntimeException(cmds.toString(), e); 149 | } 150 | } 151 | 152 | @NotNull 153 | private static File createSourceConfig(Project project, Module runConfigurationModule) throws IOException { 154 | Properties props = new Properties(); 155 | props.setProperty("source-roots", SourceRoots.resolve(project, runConfigurationModule)); 156 | 157 | File ideExecutable = getIdeExecutable(); 158 | if (ideExecutable != null) { 159 | if (ideExecutable.exists()) { 160 | props.setProperty("source-viewer", "\"" + ideExecutable.getAbsolutePath() + "\" --line {line} {file}"); 161 | } else { 162 | log.warn("Bin file not exists: " + ideExecutable.getAbsolutePath()); 163 | } 164 | } 165 | 166 | File tempFile = FileUtil.createTempFile("visualVmConfig", ".properties"); 167 | try (OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(tempFile), "UTF-8")) { 168 | props.store(osw, null); 169 | } catch (IOException e) { 170 | throw new RuntimeException(e); 171 | } 172 | return tempFile; 173 | } 174 | 175 | 176 | protected static File getIdeExecutable() { 177 | String scriptName = ApplicationNamesInfo.getInstance().getScriptName(); 178 | if (SystemInfo.isWindows) { 179 | String bits = CpuArch.CURRENT.width == 64 ? "64" : ""; 180 | return new File(PathManager.getBinPath(), scriptName + bits + ".exe"); 181 | } else if (SystemInfo.isMac) { 182 | File appDir = new File(PathManager.getHomePath(), "MacOS"); 183 | return new File(appDir, scriptName); 184 | } else if (SystemInfo.isUnix) { 185 | return new File(PathManager.getBinPath(), scriptName + ".sh"); 186 | } else { 187 | log.error("invalid OS: " + SystemInfo.getOsNameAndVersion()); 188 | return null; 189 | } 190 | } 191 | 192 | public static boolean isValidPath(String visualVmPath) { 193 | return !StringUtils.isBlank(visualVmPath) && new File(visualVmPath).exists(); 194 | } 195 | 196 | 197 | static class VisualVMProcess { 198 | 199 | private final Project project; 200 | private final String[] cmds; 201 | 202 | public VisualVMProcess(Project project, String... cmds) { 203 | this.project = project; 204 | this.cmds = cmds; 205 | } 206 | 207 | public void run() throws IOException { 208 | PluginSettings settings = ApplicationSettingsService.getInstance().getState(); 209 | 210 | List cmd = new ArrayList<>(Arrays.asList(cmds)); 211 | if (StringUtils.isNotBlank(settings.getLaf())) { 212 | cmd.add("--laf"); 213 | cmd.add(settings.getLaf()); 214 | } 215 | 216 | log.info("Starting VisualVM with parameters:" + cmd); 217 | 218 | ProcessBuilder processBuilder = new ProcessBuilder(cmd); 219 | //todo does not work 220 | // if (disableProcessDialog) { 221 | // File file = new File(PathManager.getLogPath(), "visualVMLauncher.log"); 222 | // file.createNewFile(); 223 | // if (file.exists()) { 224 | // processBuilder.redirectErrorStream(true); 225 | // processBuilder.redirectOutput(file); 226 | // } 227 | //// } 228 | Process process = processBuilder.start(); 229 | // if (!disableProcessDialog) { 230 | // process.toHandle().onExit().whenCompleteAsync((processHandle, throwable) -> accept(project, process, processHandle, throwable)); 231 | // } 232 | } 233 | 234 | // private static void accept(Project project, Process process, ProcessHandle processHandle, Throwable throwable) { 235 | // try { 236 | // if (!processHandle.isAlive()) { 237 | // if (process.exitValue() != 0) { 238 | // String err = new String(process.getErrorStream().readAllBytes(), "UTF-8"); 239 | // if (StringUtils.isNotBlank(err)) { 240 | // String message = "VisualVM exited with code: " + process.exitValue() + ".\nError: " + err; 241 | // SwingUtilities.invokeLater(() -> 242 | // Messages.showErrorDialog(project, message, "VisualVM Launcher")); 243 | // log.warn(message); 244 | // } 245 | // 246 | // } 247 | // } 248 | // } catch (Throwable e) { 249 | // log.warn(e); 250 | // } 251 | // } 252 | 253 | } 254 | 255 | public static void executeVisualVM(Project project, @NotNull String commandLineAction) { 256 | PluginSettings state = ApplicationSettingsService.getInstance().getState(); 257 | //todo needs sdk 258 | String visualVmPath = state.getVisualVmExecutable(); 259 | if (!isValidPath(visualVmPath)) { 260 | NotificationGroup group = NotificationGroupManager.getInstance().getNotificationGroup("VisualVMLauncher"); 261 | Notification notification = group.createNotification("Path to VisualVM is not valid, path='" + visualVmPath + "'", NotificationType.ERROR); 262 | ApplicationManager.getApplication().invokeLater(() -> Notifications.Bus.notify(notification)); 263 | } else { 264 | try { 265 | new VisualVMProcess(project, visualVmPath, commandLineAction).run(); 266 | } catch (IOException e) { 267 | throw new RuntimeException("visualVmPath=" + visualVmPath + "; commandLineAction=" + commandLineAction, e); 268 | } 269 | } 270 | 271 | } 272 | } 273 | -------------------------------------------------------------------------------- /src/main/java/krasa/visualvm/integration/VisualVMJavaProgramPatcher.java: -------------------------------------------------------------------------------- 1 | package krasa.visualvm.integration; 2 | 3 | import com.intellij.execution.CantRunException; 4 | import com.intellij.execution.Executor; 5 | import com.intellij.execution.configurations.JavaParameters; 6 | import com.intellij.execution.configurations.ModuleBasedConfiguration; 7 | import com.intellij.execution.configurations.RunConfigurationModule; 8 | import com.intellij.execution.configurations.RunProfile; 9 | import com.intellij.execution.runners.JavaProgramPatcher; 10 | import com.intellij.openapi.diagnostic.Logger; 11 | import com.intellij.openapi.module.Module; 12 | import com.intellij.openapi.projectRoots.Sdk; 13 | import com.intellij.openapi.projectRoots.SdkAdditionalData; 14 | import com.intellij.openapi.projectRoots.SdkTypeId; 15 | import com.intellij.openapi.projectRoots.impl.ProjectJdkImpl; 16 | import krasa.visualvm.Hacks; 17 | import krasa.visualvm.LogHelper; 18 | import krasa.visualvm.action.StartVisualVMConsoleAction; 19 | import org.apache.commons.lang3.reflect.MethodUtils; 20 | import org.jetbrains.annotations.Nullable; 21 | 22 | public class VisualVMJavaProgramPatcher extends JavaProgramPatcher { 23 | private static final Logger log = Logger.getInstance(VisualVMJavaProgramPatcher.class.getName()); 24 | long lastExecution; 25 | 26 | @Override 27 | public void patchJavaParameters(Executor executor, RunProfile configuration, JavaParameters javaParameters) { 28 | LogHelper.print("#patchJavaParameters start", this); 29 | 30 | String name = configuration.getClass().getName(); 31 | if (name.startsWith(Hacks.BUNDLED_SERVERS_RUN_PROFILE)) { 32 | LogHelper.print("patchJavaParameters " + name, this); 33 | 34 | if (System.currentTimeMillis() - lastExecution > 1000) { 35 | LogHelper.print("patchJavaParameters " + name + " patching", this); 36 | 37 | VisualVMContext visualVMContext = patch(configuration, javaParameters); 38 | StartVisualVMConsoleAction.setVisualVMContextToRecentlyCreated(visualVMContext); 39 | lastExecution = System.currentTimeMillis(); 40 | } 41 | } else { 42 | patch(configuration, javaParameters); 43 | } 44 | } 45 | 46 | private VisualVMContext patch(RunProfile configuration, JavaParameters javaParameters) { 47 | String jdkPath = getJdkPath(javaParameters); 48 | 49 | final Long appId = VisualVMHelper.getNextID(); 50 | LogHelper.print("Patching: jdkPath=" + jdkPath + "; appId=" + appId, this); 51 | javaParameters.getVMParametersList().prepend("-Dvisualvm.id=" + appId); 52 | 53 | 54 | VisualVMContext visualVMContext = new VisualVMContext(appId, jdkPath, resolveModule(configuration)); 55 | visualVMContext.save(); 56 | return visualVMContext; 57 | } 58 | 59 | @Nullable 60 | public static String getJdkPath(JavaParameters javaParameters) { 61 | String jdkPath = null; 62 | try { 63 | if (javaParameters.getJdk() != null && javaParameters.getJdk().getHomeDirectory() != null) { 64 | Sdk jdk = javaParameters.getJdk(); 65 | SdkTypeId sdkType = jdk.getSdkType(); 66 | if ("JavaSDK".equals(sdkType.getName())) { 67 | jdkPath = javaParameters.getJdkPath(); 68 | } else if ("IDEA JDK".equals(sdkType.getName())) { 69 | ProjectJdkImpl jdk1 = (ProjectJdkImpl) javaParameters.getJdk(); 70 | SdkAdditionalData sdkAdditionalData = jdk1.getSdkAdditionalData(); 71 | if (sdkAdditionalData != null) { 72 | Object javaSdk = MethodUtils.invokeMethod(sdkAdditionalData, true, "getJavaSdk"); 73 | if (javaSdk instanceof Sdk) { 74 | jdkPath = ((Sdk) javaSdk).getHomePath(); 75 | } 76 | } 77 | } 78 | } 79 | } catch (CantRunException e) { 80 | // return; 81 | } catch (Throwable e) { 82 | log.error(e); 83 | } 84 | return jdkPath; 85 | } 86 | 87 | @SuppressWarnings("rawtypes") 88 | public static Module resolveModule(RunProfile runProfile) { 89 | Module runConfigurationModule = null; 90 | if (runProfile instanceof ModuleBasedConfiguration) { 91 | ModuleBasedConfiguration configuration = (ModuleBasedConfiguration) runProfile; 92 | RunConfigurationModule configurationModule = configuration.getConfigurationModule(); 93 | if (configurationModule != null) { 94 | runConfigurationModule = configurationModule.getModule(); 95 | } 96 | } 97 | return runConfigurationModule; 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/krasa/visualvm/runner/DebugVisualVMRunner.java: -------------------------------------------------------------------------------- 1 | package krasa.visualvm.runner; 2 | 3 | import com.intellij.debugger.impl.GenericDebuggerRunner; 4 | import com.intellij.execution.ExecutionException; 5 | import com.intellij.execution.configurations.ModuleRunProfile; 6 | import com.intellij.execution.configurations.RemoteConnection; 7 | import com.intellij.execution.configurations.RunProfile; 8 | import com.intellij.execution.configurations.RunProfileState; 9 | import com.intellij.execution.jar.JarApplicationConfiguration; 10 | import com.intellij.execution.remote.RemoteConfiguration; 11 | import com.intellij.execution.runners.ExecutionEnvironment; 12 | import com.intellij.execution.ui.RunContentDescriptor; 13 | import com.intellij.openapi.diagnostic.Logger; 14 | import krasa.visualvm.LogHelper; 15 | import krasa.visualvm.MyConfigurable; 16 | import krasa.visualvm.executor.DebugVisualVMExecutor; 17 | import org.jetbrains.annotations.NotNull; 18 | import org.jetbrains.annotations.Nullable; 19 | 20 | public class DebugVisualVMRunner extends GenericDebuggerRunner { 21 | private static final Logger log = Logger.getInstance(DebugVisualVMRunner.class.getName()); 22 | 23 | @NotNull 24 | public String getRunnerId() { 25 | return DebugVisualVMExecutor.EXECUTOR_ID; 26 | } 27 | 28 | @Override 29 | public void execute(@NotNull final ExecutionEnvironment environment) 30 | throws ExecutionException { 31 | LogHelper.print("#execute", this); 32 | 33 | boolean b = MyConfigurable.openSettingsIfNotConfigured(environment.getProject()); 34 | if (!b) { 35 | return; 36 | } 37 | super.execute(environment); 38 | } 39 | 40 | public boolean canRun(@NotNull String executorId, @NotNull RunProfile profile) { 41 | return executorId.equals(DebugVisualVMExecutor.EXECUTOR_ID) && (profile instanceof ModuleRunProfile || profile instanceof JarApplicationConfiguration) 42 | && !(profile instanceof RemoteConfiguration); 43 | } 44 | 45 | @Nullable 46 | @Override 47 | protected RunContentDescriptor attachVirtualMachine(RunProfileState state, @NotNull ExecutionEnvironment env, 48 | RemoteConnection connection, boolean pollConnection) throws ExecutionException { 49 | RunContentDescriptor runContentDescriptor = super.attachVirtualMachine(state, env, connection, pollConnection); 50 | LogHelper.print("#attachVirtualMachine", this); 51 | RunnerUtils.runVisualVM(this, env, state); 52 | return runContentDescriptor; 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/krasa/visualvm/runner/RunVisualVMRunner.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of VisualVM for IDEA 3 | * 4 | * Copyright (c) 2008, Esko Luontola. All Rights Reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without modification, 7 | * are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright notice, 10 | * this list of conditions and the following disclaimer. 11 | * 12 | * * Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * 16 | * * Neither the name of the copyright holder nor the names of its contributors 17 | * may be used to endorse or promote products derived from this software 18 | * without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 24 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 27 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | package krasa.visualvm.runner; 33 | 34 | import com.intellij.execution.ExecutionException; 35 | import com.intellij.execution.configurations.ModuleRunProfile; 36 | import com.intellij.execution.configurations.RunProfile; 37 | import com.intellij.execution.configurations.RunProfileState; 38 | import com.intellij.execution.impl.DefaultJavaProgramRunner; 39 | import com.intellij.execution.jar.JarApplicationConfiguration; 40 | import com.intellij.execution.remote.RemoteConfiguration; 41 | import com.intellij.execution.runners.ExecutionEnvironment; 42 | import com.intellij.execution.target.TargetEnvironmentAwareRunProfileState; 43 | import com.intellij.execution.ui.RunContentDescriptor; 44 | import com.intellij.openapi.diagnostic.Logger; 45 | import krasa.visualvm.MyConfigurable; 46 | import krasa.visualvm.executor.RunVisualVMExecutor; 47 | import org.jetbrains.annotations.NotNull; 48 | import org.jetbrains.concurrency.Promise; 49 | 50 | public class RunVisualVMRunner extends DefaultJavaProgramRunner { 51 | private static final Logger log = Logger.getInstance(DebugVisualVMRunner.class.getName()); 52 | 53 | @NotNull 54 | public String getRunnerId() { 55 | return RunVisualVMExecutor.RUN_WITH_VISUAL_VM; 56 | } 57 | 58 | public boolean canRun(@NotNull String executorId, @NotNull RunProfile profile) { 59 | return executorId.equals(RunVisualVMExecutor.RUN_WITH_VISUAL_VM) && (profile instanceof ModuleRunProfile || profile instanceof JarApplicationConfiguration) && !(profile instanceof RemoteConfiguration); 60 | } 61 | 62 | @Override 63 | public void execute(@NotNull final ExecutionEnvironment env) throws ExecutionException { 64 | boolean b = MyConfigurable.openSettingsIfNotConfigured(env.getProject()); 65 | if (!b) { 66 | return; 67 | } 68 | super.execute(env); 69 | } 70 | 71 | @Override 72 | protected RunContentDescriptor doExecute(@NotNull RunProfileState state, @NotNull ExecutionEnvironment env) 73 | throws ExecutionException { 74 | RunContentDescriptor runContentDescriptor = super.doExecute(state, env); 75 | RunnerUtils.runVisualVM(this, env, state); 76 | return runContentDescriptor; 77 | } 78 | 79 | @Override 80 | protected @NotNull Promise doExecuteAsync(@NotNull TargetEnvironmentAwareRunProfileState state, @NotNull ExecutionEnvironment env) throws ExecutionException { 81 | Promise runContentDescriptorPromise = super.doExecuteAsync(state, env); 82 | RunnerUtils.runVisualVM(this, env, state); 83 | return runContentDescriptorPromise; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/krasa/visualvm/runner/RunnerUtils.java: -------------------------------------------------------------------------------- 1 | package krasa.visualvm.runner; 2 | 3 | import com.intellij.execution.ExecutionException; 4 | import com.intellij.execution.configurations.RunProfileState; 5 | import com.intellij.execution.runners.ExecutionEnvironment; 6 | import com.intellij.execution.runners.JvmPatchableProgramRunner; 7 | import com.intellij.openapi.diagnostic.Logger; 8 | import krasa.visualvm.ApplicationSettingsService; 9 | import krasa.visualvm.Hacks; 10 | import krasa.visualvm.LogHelper; 11 | import krasa.visualvm.integration.VisualVMContext; 12 | import krasa.visualvm.integration.VisualVMHelper; 13 | 14 | public class RunnerUtils { 15 | private static final Logger log = Logger.getInstance(RunnerUtils.class.getName()); 16 | 17 | static void runVisualVM(final JvmPatchableProgramRunner runner, ExecutionEnvironment env, RunProfileState state) throws ExecutionException { 18 | try { 19 | // tomcat uses PatchedLocalState 20 | if (state.getClass().getSimpleName().equals(Hacks.BUNDLED_SERVERS_RUN_PROFILE_STATE)) { 21 | LogHelper.print("#runVisualVM ExecutionEnvironment", runner); 22 | new Thread() { 23 | @Override 24 | public void run() { 25 | LogHelper.print("#Thread run", this); 26 | try { 27 | Thread.sleep(ApplicationSettingsService.getInstance().getState().getDelayForVisualVMStartAsLong()); 28 | VisualVMHelper.startVisualVM(VisualVMContext.load(), env.getProject(), runner); 29 | } catch (Throwable e) { 30 | log.error(e); 31 | } 32 | } 33 | }.start(); 34 | } else { 35 | VisualVMHelper.startVisualVM(VisualVMContext.load(), env.getProject(), runner); 36 | } 37 | } catch (Throwable e) { 38 | log.error(e); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | VisualVMLauncher 3 | VisualVM Launcher 4 | 5 | Vojtech 6 | Krasa 7 | 8 | 9 | VisualVM integration.
11 | Use buttons from the main toolbar to start VisualVM along with executed application, 12 | or button next to the console window of already started application. 13 |

14 | Donations | GitHub | Issues 15 | ]]>
16 | 17 | 18 | 19 | 20 | 21 | 22 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 51 | 52 | 53 | 54 | com.intellij.modules.java 55 | 56 |
-------------------------------------------------------------------------------- /src/main/resources/META-INF/pluginIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 20 | 22 | image/svg+xml 23 | 25 | 26 | 27 | 28 | 29 | 31 | 33 | 39 | 40 | 48 | 51 | 55 | 56 | 58 | 64 | 65 | 73 | 76 | 80 | 81 | 83 | 89 | 90 | 91 | 112 | 118 | 124 | 125 | -------------------------------------------------------------------------------- /src/main/resources/krasa/visualvm/debug13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasa/VisualVMLauncher/5b97f289ee5a9cf2938e97ff5a6f37af6558c369/src/main/resources/krasa/visualvm/debug13.png -------------------------------------------------------------------------------- /src/main/resources/krasa/visualvm/debug13@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasa/VisualVMLauncher/5b97f289ee5a9cf2938e97ff5a6f37af6558c369/src/main/resources/krasa/visualvm/debug13@2x.png -------------------------------------------------------------------------------- /src/main/resources/krasa/visualvm/debug13@2x_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasa/VisualVMLauncher/5b97f289ee5a9cf2938e97ff5a6f37af6558c369/src/main/resources/krasa/visualvm/debug13@2x_dark.png -------------------------------------------------------------------------------- /src/main/resources/krasa/visualvm/debug13_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasa/VisualVMLauncher/5b97f289ee5a9cf2938e97ff5a6f37af6558c369/src/main/resources/krasa/visualvm/debug13_dark.png -------------------------------------------------------------------------------- /src/main/resources/krasa/visualvm/run13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasa/VisualVMLauncher/5b97f289ee5a9cf2938e97ff5a6f37af6558c369/src/main/resources/krasa/visualvm/run13.png -------------------------------------------------------------------------------- /src/main/resources/krasa/visualvm/run13@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasa/VisualVMLauncher/5b97f289ee5a9cf2938e97ff5a6f37af6558c369/src/main/resources/krasa/visualvm/run13@2x.png -------------------------------------------------------------------------------- /src/main/resources/krasa/visualvm/run13@2x_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasa/VisualVMLauncher/5b97f289ee5a9cf2938e97ff5a6f37af6558c369/src/main/resources/krasa/visualvm/run13@2x_dark.png -------------------------------------------------------------------------------- /src/main/resources/krasa/visualvm/run13_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/krasa/VisualVMLauncher/5b97f289ee5a9cf2938e97ff5a6f37af6558c369/src/main/resources/krasa/visualvm/run13_dark.png -------------------------------------------------------------------------------- /src/main/resources/krasa/visualvm/svg/console16.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 20 | 22 | image/svg+xml 23 | 25 | 26 | 27 | 28 | 29 | 31 | 33 | 39 | 40 | 48 | 51 | 55 | 56 | 58 | 64 | 65 | 73 | 76 | 80 | 81 | 83 | 89 | 90 | 91 | 111 | 117 | 123 | 124 | -------------------------------------------------------------------------------- /src/main/resources/krasa/visualvm/svg/console16_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 20 | 22 | image/svg+xml 23 | 25 | 26 | 27 | 28 | 29 | 31 | 33 | 39 | 40 | 48 | 51 | 55 | 56 | 58 | 64 | 65 | 73 | 76 | 80 | 81 | 83 | 89 | 90 | 91 | 111 | 117 | 123 | 124 | -------------------------------------------------------------------------------- /src/main/resources/krasa/visualvm/svg/debug16.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 20 | 22 | image/svg+xml 23 | 25 | 26 | 27 | 28 | 29 | 31 | 33 | 39 | 40 | 48 | 51 | 55 | 56 | 58 | 64 | 65 | 73 | 76 | 80 | 81 | 84 | 89 | 90 | 91 | 111 | 118 | 124 | 125 | -------------------------------------------------------------------------------- /src/main/resources/krasa/visualvm/svg/debug16_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 20 | 22 | image/svg+xml 23 | 25 | 26 | 27 | 28 | 29 | 31 | 33 | 39 | 40 | 48 | 51 | 55 | 56 | 58 | 64 | 65 | 73 | 76 | 80 | 81 | 84 | 89 | 90 | 91 | 111 | 118 | 124 | 125 | -------------------------------------------------------------------------------- /src/main/resources/krasa/visualvm/svg/run16.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 20 | 22 | image/svg+xml 23 | 25 | 26 | 27 | 28 | 29 | 31 | 33 | 39 | 40 | 48 | 51 | 55 | 56 | 58 | 64 | 65 | 73 | 76 | 80 | 81 | 84 | 89 | 90 | 91 | 111 | 118 | 123 | 124 | -------------------------------------------------------------------------------- /src/main/resources/krasa/visualvm/svg/run16_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 20 | 22 | image/svg+xml 23 | 25 | 26 | 27 | 28 | 29 | 31 | 33 | 39 | 40 | 48 | 51 | 55 | 56 | 58 | 64 | 65 | 73 | 76 | 80 | 81 | 84 | 89 | 90 | 91 | 111 | 118 | 123 | 124 | --------------------------------------------------------------------------------