Skip to content

Commit d44b29b

Browse files
taigacontangzx
authored andcommitted
Unity Attach Debugger support (#202)
Unity Attach support
1 parent 5604692 commit d44b29b

13 files changed

+607
-63
lines changed

src/main/java/com/tang/intellij/lua/debugger/attach/LuaLocalAttachDebugger.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import com.intellij.xdebugger.XDebugProcessStarter
2424
import com.intellij.xdebugger.XDebugSession
2525
import com.intellij.xdebugger.XDebuggerManager
2626
import com.intellij.xdebugger.attach.XLocalAttachDebugger
27+
import com.tang.intellij.lua.debugger.utils.ProcessDetailInfo
28+
import com.tang.intellij.lua.debugger.utils.getDisplayName
2729

2830
/**
2931
*

src/main/java/com/tang/intellij/lua/debugger/attach/LuaLocalAttachDebuggerProvider.kt

Lines changed: 5 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -16,33 +16,16 @@
1616

1717
package com.tang.intellij.lua.debugger.attach
1818

19-
import com.intellij.execution.configurations.GeneralCommandLine
2019
import com.intellij.execution.process.ProcessInfo
21-
import com.intellij.execution.util.ExecUtil
2220
import com.intellij.openapi.project.Project
2321
import com.intellij.openapi.util.Key
2422
import com.intellij.openapi.util.UserDataHolder
2523
import com.intellij.xdebugger.attach.XLocalAttachDebugger
2624
import com.intellij.xdebugger.attach.XLocalAttachDebuggerProvider
2725
import com.intellij.xdebugger.attach.XLocalAttachGroup
28-
import com.tang.intellij.lua.psi.LuaFileUtil
29-
import java.io.ByteArrayInputStream
26+
import com.tang.intellij.lua.debugger.utils.ProcessDetailInfo
27+
import com.tang.intellij.lua.debugger.utils.ProcessUtils
3028
import java.util.*
31-
import javax.xml.parsers.DocumentBuilderFactory
32-
33-
data class ProcessDetailInfo(var pid: Int = 0, var path: String = "", var title: String = "")
34-
35-
private const val MAX_DISPLAY_LEN = 60
36-
37-
internal fun getDisplayName(processInfo: ProcessInfo, detailInfo: ProcessDetailInfo): String {
38-
val s = if (detailInfo.title.isNotEmpty())
39-
"${processInfo.executableName} - ${detailInfo.title}"
40-
else processInfo.executableName
41-
42-
if (s.length > MAX_DISPLAY_LEN)
43-
return "${s.substring(0, MAX_DISPLAY_LEN)}..."
44-
return s
45-
}
4629

4730
/**
4831
*
@@ -53,57 +36,16 @@ class LuaLocalAttachDebuggerProvider : XLocalAttachDebuggerProvider {
5336
override fun getAttachGroup(): XLocalAttachGroup = LuaLocalAttachGroup.INSTANCE
5437

5538
companion object {
56-
val DETAIL_KEY = Key.create<MutableMap<Int, ProcessDetailInfo>>("LuaLocalAttachDebuggerProvider.key")
39+
val DETAIL_KEY = Key.create<Map<Int, ProcessDetailInfo>>("LuaLocalAttachDebuggerProvider.key")
5740
}
5841

59-
private val processMap = mutableMapOf<Int, ProcessDetailInfo>()
60-
61-
private fun listProcesses() {
62-
processMap.clear()
63-
val archExe = LuaFileUtil.getArchExeFile()
64-
val commandLine = GeneralCommandLine(archExe)
65-
//commandLine.charset = Charset.forName("UTF-8")
66-
commandLine.addParameters("list_processes")
67-
68-
val processOutput = ExecUtil.execAndGetOutput(commandLine)
69-
70-
val text = processOutput.stdout
71-
val builder = DocumentBuilderFactory.newInstance()
72-
val documentBuilder = builder.newDocumentBuilder()
73-
val document = documentBuilder.parse(ByteArrayInputStream(text.toByteArray()))
74-
val root = document.documentElement
75-
root.childNodes.let {
76-
for (i in 0 until it.length) {
77-
val c = it.item(i)
78-
val p = ProcessDetailInfo()
79-
val map = c.attributes
80-
map.getNamedItem("pid")?.let {
81-
p.pid = it.nodeValue.toInt()
82-
}
83-
val childNodes = c.childNodes
84-
for (j in 0 until childNodes.length) {
85-
val child = childNodes.item(j)
86-
when (child.nodeName) {
87-
"title" -> {
88-
val item = child.childNodes.item(0)
89-
p.title = item?.nodeValue ?: ""
90-
}
91-
"path" -> {
92-
val item = child.childNodes.item(0)
93-
p.path = item?.nodeValue ?: ""
94-
}
95-
}
96-
}
97-
processMap[p.pid] = p
98-
}
99-
}
100-
}
42+
private var processMap = mapOf<Int, ProcessDetailInfo>()
10143

10244
override fun getAvailableDebuggers(project: Project, processInfo: ProcessInfo, userDataHolder: UserDataHolder): List<XLocalAttachDebugger> {
10345

10446
val b = userDataHolder.getUserData(DETAIL_KEY)
10547
if (b == null) {
106-
listProcesses()
48+
processMap = ProcessUtils.listProcesses()
10749
userDataHolder.putUserData(DETAIL_KEY, processMap)
10850
}
10951

src/main/java/com/tang/intellij/lua/debugger/attach/LuaLocalAttachGroup.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import com.intellij.execution.process.ProcessInfo
2020
import com.intellij.openapi.project.Project
2121
import com.intellij.openapi.util.UserDataHolder
2222
import com.intellij.xdebugger.attach.XLocalAttachGroup
23+
import com.tang.intellij.lua.debugger.utils.getDisplayName
2324
import com.tang.intellij.lua.lang.LuaIcons
2425
import com.tang.intellij.lua.lang.LuaLanguage
2526
import sun.awt.shell.ShellFolder
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* Copyright (c) 2017. tangzx([email protected])
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.tang.intellij.lua.debugger.remote
18+
19+
import com.intellij.execution.ExecutionException
20+
import com.intellij.execution.Executor
21+
import com.intellij.execution.configurations.ConfigurationFactory
22+
import com.intellij.execution.configurations.RunConfiguration
23+
import com.intellij.execution.configurations.RunProfileState
24+
import com.intellij.execution.runners.ExecutionEnvironment
25+
import com.intellij.execution.runners.RunConfigurationWithSuppressedDefaultRunAction
26+
import com.intellij.openapi.module.Module
27+
import com.intellij.openapi.options.SettingsEditor
28+
import com.intellij.openapi.options.SettingsEditorGroup
29+
import com.intellij.openapi.project.Project
30+
import com.intellij.openapi.util.InvalidDataException
31+
import com.intellij.openapi.util.JDOMExternalizerUtil
32+
import com.intellij.openapi.util.WriteExternalException
33+
import com.tang.intellij.lua.debugger.LuaCommandLineState
34+
import com.tang.intellij.lua.debugger.LuaRunConfiguration
35+
import com.tang.intellij.lua.debugger.unity.LuaUnitySettingsEditor
36+
import org.jdom.Element
37+
38+
/**
39+
*
40+
* Created by Taigacon on 2018/11/6.
41+
*/
42+
class LuaUnityConfiguration(project: Project, factory: ConfigurationFactory)
43+
: LuaRunConfiguration(project, factory), RunConfigurationWithSuppressedDefaultRunAction {
44+
45+
var preferedUnityInstanceName: String = ""
46+
47+
override fun checkConfiguration() {
48+
super.checkConfiguration()
49+
checkSourceRoot()
50+
}
51+
52+
override fun getValidModules(): Collection<Module> {
53+
//final Module[] modules = ModuleManager.getInstance(getProject()).getModules();
54+
return emptyList()
55+
}
56+
57+
override fun getConfigurationEditor(): SettingsEditor<out RunConfiguration> {
58+
val group = SettingsEditorGroup<LuaUnityConfiguration>()
59+
group.addEditor("unity", LuaUnitySettingsEditor())
60+
return group
61+
}
62+
63+
@Throws(ExecutionException::class)
64+
override fun getState(executor: Executor, executionEnvironment: ExecutionEnvironment): RunProfileState? {
65+
return LuaCommandLineState(executionEnvironment)
66+
}
67+
68+
@Throws(WriteExternalException::class)
69+
override fun writeExternal(element: Element) {
70+
super.writeExternal(element)
71+
JDOMExternalizerUtil.writeField(element, "PreferedUnityInstanceName", preferedUnityInstanceName)
72+
}
73+
74+
@Throws(InvalidDataException::class)
75+
override fun readExternal(element: Element) {
76+
super.readExternal(element)
77+
val preferedUnityInstanceName = JDOMExternalizerUtil.readField(element, "PreferedUnityInstanceName")
78+
if (preferedUnityInstanceName != null)
79+
this.preferedUnityInstanceName = preferedUnityInstanceName
80+
}
81+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright (c) 2017. tangzx([email protected])
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.tang.intellij.lua.debugger.unity;
18+
19+
import com.intellij.execution.BeforeRunTask;
20+
import com.intellij.execution.configurations.ConfigurationFactory;
21+
import com.intellij.execution.configurations.RunConfiguration;
22+
import com.intellij.openapi.project.Project;
23+
import com.intellij.openapi.util.Key;
24+
import com.tang.intellij.lua.debugger.remote.LuaUnityConfiguration;
25+
import org.jetbrains.annotations.NotNull;
26+
27+
/**
28+
*
29+
* Created by Taigacon on 2018/11/6.
30+
*/
31+
public class LuaUnityConfigurationFactory extends ConfigurationFactory {
32+
33+
public LuaUnityConfigurationFactory(LuaUnityConfigurationType type) {
34+
super(type);
35+
}
36+
37+
@NotNull
38+
@Override
39+
public RunConfiguration createTemplateConfiguration(@NotNull Project project) {
40+
return new LuaUnityConfiguration(project, this);
41+
}
42+
43+
@Override
44+
public void configureBeforeRunTaskDefaults(Key<? extends BeforeRunTask> providerID, BeforeRunTask task) {
45+
if ("Make".equals(providerID.toString()))
46+
task.setEnabled(false);
47+
}
48+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Copyright (c) 2017. tangzx([email protected])
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.tang.intellij.lua.debugger.unity;
18+
19+
import com.intellij.execution.configurations.ConfigurationFactory;
20+
import com.intellij.execution.configurations.ConfigurationType;
21+
import com.intellij.execution.configurations.ConfigurationTypeUtil;
22+
import com.tang.intellij.lua.lang.LuaIcons;
23+
import org.jetbrains.annotations.NotNull;
24+
25+
import javax.swing.*;
26+
27+
/**
28+
*
29+
* Created by Taigacon on 2018/11/6.
30+
*/
31+
public class LuaUnityConfigurationType implements ConfigurationType {
32+
33+
private final LuaUnityConfigurationFactory factory = new LuaUnityConfigurationFactory(this);
34+
35+
public static LuaUnityConfigurationType getInstance() {
36+
return ConfigurationTypeUtil.findConfigurationType(LuaUnityConfigurationType.class);
37+
}
38+
39+
@Override
40+
public String getDisplayName() {
41+
return "Lua Attach Unity";
42+
}
43+
44+
@Override
45+
public String getConfigurationTypeDescription() {
46+
return "Lua Attach Debugger";
47+
}
48+
49+
@Override
50+
public Icon getIcon() {
51+
return LuaIcons.FILE;
52+
}
53+
54+
@NotNull
55+
@Override
56+
public String getId() {
57+
return "lua.unitydebug";
58+
}
59+
60+
@Override
61+
public ConfigurationFactory[] getConfigurationFactories() {
62+
return new ConfigurationFactory[] { factory };
63+
}
64+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* Copyright (c) 2017. tangzx([email protected])
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.tang.intellij.lua.debugger.unity
18+
19+
import com.intellij.execution.process.ProcessInfo
20+
import com.intellij.xdebugger.XDebugSession
21+
import com.tang.intellij.lua.debugger.attach.LuaAttachBridge
22+
import com.tang.intellij.lua.debugger.attach.LuaAttachBridgeBase
23+
import com.tang.intellij.lua.debugger.attach.LuaAttachDebugProcessBase
24+
import com.tang.intellij.lua.debugger.remote.LuaUnityConfiguration
25+
import com.tang.intellij.lua.debugger.utils.ProcessUtils
26+
27+
/**
28+
*
29+
* Created by Taigacon on 2018/11/6.
30+
*/
31+
class LuaUnityDebugProcess internal constructor(session: XDebugSession, private val configuration: LuaUnityConfiguration)
32+
: LuaAttachDebugProcessBase(session) {
33+
34+
private fun queryUnityProcess(): ProcessInfo? {
35+
val list = UnityProcessDiscovery.getAttachableProcesses(GetProcessOptions.All)
36+
if (list.isNotEmpty()) {
37+
var processMap = ProcessUtils.listProcesses()
38+
for (processInfo in list) {
39+
processMap[processInfo.pid]?.run {
40+
if (title.contains(configuration.preferedUnityInstanceName, false)) {
41+
return processInfo
42+
}
43+
}
44+
}
45+
}
46+
return null
47+
}
48+
49+
override fun startBridge(): LuaAttachBridgeBase {
50+
val bridge = LuaAttachBridge(this, session)
51+
this.bridge = bridge
52+
bridge.setProtoHandler(this)
53+
val processInfo = queryUnityProcess()
54+
if (processInfo == null) {
55+
if (configuration.preferedUnityInstanceName.isNotEmpty())
56+
error("Cannot find suitable Unity instance for prefered instance name: ${configuration.preferedUnityInstanceName}")
57+
else
58+
error("Cannot find suitable Unity instance")
59+
session.stop()
60+
} else {
61+
bridge.attach(processInfo)
62+
}
63+
return bridge
64+
}
65+
}

0 commit comments

Comments
 (0)