1
1
package processing.app.gradle
2
2
3
- import com.sun.jdi.ObjectReference
3
+ import com.sun.jdi.Location
4
4
import com.sun.jdi.StackFrame
5
- import com.sun.jdi.StringReference
6
5
import com.sun.jdi.VirtualMachine
7
6
import com.sun.jdi.event.ExceptionEvent
8
7
import com.sun.jdi.request.EventRequest
9
- import kotlinx.coroutines.CoroutineScope
10
- import kotlinx.coroutines.Dispatchers
11
8
import kotlinx.coroutines.delay
12
- import kotlinx.coroutines.launch
13
9
import processing.app.Messages
10
+ import processing.app.SketchException
11
+ import processing.app.ui.Editor
14
12
15
13
// TODO: Consider adding a panel to the footer
16
- class Exceptions {
17
- companion object {
18
- suspend fun listen (vm : VirtualMachine ) {
19
- try {
20
- val manager = vm.eventRequestManager()
14
+ class Exceptions (val vm : VirtualMachine , val editor : Editor ? ) {
15
+ suspend fun listen () {
16
+ try {
17
+ val manager = vm.eventRequestManager()
21
18
22
- val request = manager.createExceptionRequest(null , false , true )
23
- request.setSuspendPolicy(EventRequest .SUSPEND_EVENT_THREAD )
24
- request.enable()
19
+ val request = manager.createExceptionRequest(null , false , true )
20
+ request.setSuspendPolicy(EventRequest .SUSPEND_EVENT_THREAD )
21
+ request.enable()
25
22
26
- val queue = vm.eventQueue()
27
- while (true ) {
28
- val eventSet = queue.remove()
29
- for (event in eventSet) {
30
- if (event is ExceptionEvent ) {
31
- printExceptionDetails(event)
32
- event.thread().resume()
33
- }
23
+ val queue = vm.eventQueue()
24
+ while (true ) {
25
+ val eventSet = queue.remove()
26
+ for (event in eventSet) {
27
+ if (event is ExceptionEvent ) {
28
+ printExceptionDetails(event)
29
+ event.thread().resume()
34
30
}
35
- eventSet.resume()
36
- delay(10 )
37
31
}
38
- } catch (e : Exception ) {
39
- Messages .log( " Error while listening for exceptions: ${e.message} " )
32
+ eventSet.resume()
33
+ delay( 10 )
40
34
}
35
+ } catch (e: Exception ) {
36
+ Messages .log(" Error while listening for exceptions: ${e.message} " )
41
37
}
38
+ }
42
39
43
- fun printExceptionDetails (event : ExceptionEvent ) {
44
- val exception = event.exception()
45
- val thread = event.thread()
46
- val location = event.location()
47
- val stackFrames = thread.frames()
40
+ fun printExceptionDetails (event : ExceptionEvent ) {
41
+ val exception = event.exception()
42
+ val thread = event.thread()
43
+ val location = event.location().mapToPdeFile ()
44
+ val stackFrames = thread.frames()
48
45
49
- println (" \n 🚨 Exception Caught 🚨" )
50
- println (" Type : ${exception.referenceType().name()} " )
51
- // TODO: Fix exception message retrieval
52
- // println("Message : ${getExceptionMessage(exception)}")
53
- println (" Thread : ${thread.name()} " )
54
- println (" Location : ${location.sourcePath()} :${location.lineNumber()} \n " )
46
+ val (processingFrames, userFrames) = stackFrames
47
+ .map{
48
+ val location = it.location().mapToPdeFile()
49
+ val method = location.method()
50
+ it to " ${method.declaringType().name()} .${method.name()} () @ ${location.sourcePath()} :${location.lineNumber()} "
51
+ }
52
+ .partition {
53
+ it.first.location().declaringType().name().startsWith(" processing." )
54
+ }
55
55
56
- // TODO: Map to .pde file again
57
- // TODO: Communicate back to Editor
56
+ /*
57
+ We have 6 lines by default within the editor to display more information about the exception.
58
+ */
58
59
59
- // Separate stack frames
60
- val userFrames = mutableListOf<StackFrame >()
61
- val processingFrames = mutableListOf<StackFrame >()
60
+ val message = """
61
+ In Processing code:
62
+ #processingFrames
63
+
64
+ In your code:
65
+ #userFrames
66
+
67
+ """
68
+ .trimIndent()
69
+ .replace(" #processingFrames" , processingFrames.joinToString(" \n " ) { it.second })
70
+ .replace(" #userFrames" , userFrames.joinToString(" \n " ) { it.second })
62
71
63
- stackFrames.forEach { frame ->
64
- val className = frame.location().declaringType().name()
65
- if (className.startsWith(" processing." )) {
66
- processingFrames.add(frame)
67
- } else {
68
- userFrames.add(frame)
69
- }
70
- }
72
+ val error = """
73
+ Exception: ${exception.referenceType().name()} @ ${location.sourcePath()} :${location.lineNumber()}
74
+ """ .trimIndent()
71
75
72
- // Print user frames first
73
- println (" 🔍 Stacktrace (Your Code First):" )
74
- userFrames.forEachIndexed { index, frame -> printStackFrame(index, frame) }
76
+ println (message)
77
+ System .err.println (error)
75
78
76
- // Print Processing frames second
77
- if (processingFrames.isNotEmpty()) {
78
- println (" \n 🔧 Processing Stacktrace (Hidden Initially):" )
79
- processingFrames.forEachIndexed { index, frame -> printStackFrame(index, frame) }
80
- }
79
+ editor?.statusError(exception.referenceType().name())
80
+ }
81
81
82
- println ( " ────────────────────────────────── \n " )
83
- }
82
+ fun Location. mapToPdeFile (): Location {
83
+ if (editor == null ) return this
84
84
85
- fun printStackFrame (index : Int , frame : StackFrame ) {
86
- val location = frame.location()
87
- val method = location.method()
88
- println (
89
- " #$index ${location.sourcePath()} :${location.lineNumber()} -> ${
90
- method.declaringType().name()
91
- } .${method.name()} ()"
92
- )
85
+ // Check if the source is a .java file
86
+ val sketch = editor.sketch
87
+ sketch.code.forEach { code ->
88
+ if (code.extension != " java" ) return @forEach
89
+ if (sourceName() != code.fileName) return @forEach
90
+ return @mapToPdeFile this
93
91
}
94
92
95
- // Extracts the exception's message
96
- fun getExceptionMessage (exception : ObjectReference ): String {
97
- val messageMethod = exception.referenceType().methodsByName(" getMessage" ).firstOrNull() ? : return " Unknown"
98
- val messageValue =
99
- exception.invokeMethod(null , messageMethod, emptyList(), ObjectReference .INVOKE_SINGLE_THREADED )
100
- return (messageValue as ? StringReference )?.value() ? : " Unknown"
101
- }
93
+ // TODO: Map to .pde file again, @see JavaBuild.placeException
94
+ // BLOCKED: Because we don't run the JavaBuild code.prepocOffset is empty
95
+
96
+ return this
102
97
}
103
98
}
0 commit comments