FazBrowse GitHub Viewer
|
Trending
|
URL:
|
Home
Tools:
[Download Repo ZIP]
[View Raw Code]
[Original HTTPS Page]
Dart-Code/src/debug/web_debug_impl.ts at master · optifact/Dart-Code · GitHub
Uh oh!
There was an error while loading.
Please reload this page
.
optifact
/
Dart-Code
Public
forked from
Dart-Code/Dart-Code
Notifications
You must be signed in to change notification settings
Fork
0
Star
0
Code
Pull requests
0
Actions
Projects
Security and quality
0
Insights
Additional navigation options
Code
Pull requests
Actions
Projects
Security and quality
Insights
Expand file tree
Breadcrumbs
Dart-Code
/
src
/
debug
/
web_debug_impl.ts
Copy path
More file actions
More file actions
Latest commit
History
History
History
316 lines (279 loc) · 11.4 KB
Breadcrumbs
Dart-Code
/
src
/
debug
/
web_debug_impl.ts
Copy path
File metadata and controls
316 lines (279 loc) · 11.4 KB
Raw
Copy raw file
Download raw file
Open symbols panel
Edit and raw actions
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
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
import
{
ContinuedEvent
,
Event
,
OutputEvent
,
TerminatedEvent
}
from
"@vscode/debugadapter"
;
import
{
DebugProtocol
}
from
"@vscode/debugprotocol"
;
import
{
FlutterCapabilities
}
from
"../shared/capabilities/flutter"
;
import
{
debugLaunchProgressId
,
restartReasonManual
}
from
"../shared/constants"
;
import
{
DartLaunchArgs
}
from
"../shared/debug/interfaces"
;
import
{
LogCategory
}
from
"../shared/enums"
;
import
{
AppProgress
}
from
"../shared/flutter/daemon_interfaces"
;
import
{
Logger
,
SpawnedProcess
}
from
"../shared/interfaces"
;
import
{
getPubExecutionInfo
}
from
"../shared/processes"
;
import
{
errorString
,
usingCustomScript
}
from
"../shared/utils"
;
import
{
DartDebugSession
}
from
"./dart_debug_impl"
;
import
{
VMEvent
}
from
"./dart_debug_protocol"
;
import
{
DebugAdapterLogger
}
from
"./logging"
;
import
{
WebRun
}
from
"./run_daemon"
;
const
objectGroupName
=
"my-group"
;
const
flutterExceptionStartBannerPrefix
=
"══╡ EXCEPTION CAUGHT BY"
;
const
flutterExceptionEndBannerPrefix
=
"══════════════════════════════════════════"
;
export
class
WebDebugSession
extends
DartDebugSession
{
private
runDaemon
?:
WebRun
;
private
currentRunningAppId
?:
string
;
private
appHasStarted
=
false
;
private
appHasBeenToldToStopOrDetach
=
false
;
private
vmServiceUri
?:
string
;
protected
readonly
flutterCapabilities
=
FlutterCapabilities
.
empty
;
// Allow flipping into stderr mode for red exceptions when we see the start/end of a Flutter exception dump.
private
outputCategory
:
"stdout"
|
"stderr"
|
"console"
=
"console"
;
constructor
(
)
{
super
(
)
;
this
.
sendStdOutToConsole
=
false
;
// We get the VM service URI from the `flutter run` process. If we parse
// it out of verbose logging and connect to it, it'll be before Flutter is
// finished setting up and bad things can happen (like us sending events
// way too early).
this
.
parseVmServiceUriFromStdOut
=
false
;
this
.
requiresProgram
=
false
;
this
.
logCategory
=
LogCategory
.
WebDaemon
;
}
protected
initializeRequest
(
response
:
DebugProtocol
.
InitializeResponse
,
args
:
DebugProtocol
.
InitializeRequestArguments
,
)
:
void
{
response
.
body
=
response
.
body
||
{
}
;
response
.
body
.
supportsRestartRequest
=
true
;
super
.
initializeRequest
(
response
,
args
)
;
}
protected
async
spawnProcess
(
args
:
DartLaunchArgs
)
:
Promise
<
SpawnedProcess
>
{
const
logger
=
new
DebugAdapterLogger
(
this
,
this
.
logCategory
)
;
this
.
expectAdditionalPidToTerminate
=
true
;
this
.
runDaemon
=
this
.
spawnRunDaemon
(
args
,
logger
)
;
this
.
runDaemon
.
registerForUnhandledMessages
(
(
msg
)
=>
this
.
handleLogOutput
(
msg
)
)
;
// Set up subscriptions.
this
.
runDaemon
.
registerForDaemonConnect
(
(
n
)
=>
this
.
recordAdditionalPid
(
n
.
pid
)
)
;
this
.
runDaemon
.
registerForAppStart
(
(
n
)
=>
this
.
currentRunningAppId
=
n
.
appId
)
;
this
.
runDaemon
.
registerForAppDebugPort
(
async
(
n
)
=>
{
this
.
vmServiceUri
=
n
.
wsUri
;
await
this
.
connectToVmServiceIfReady
(
)
;
}
)
;
this
.
runDaemon
.
registerForAppStarted
(
async
(
n
)
=>
{
this
.
appHasStarted
=
true
;
this
.
outputCategory
=
"stdout"
;
// In modes like Profile, we'll never connect the debugger, so
// we should end our progress reporting here.
if
(
!
this
.
vmServiceUri
)
this
.
endProgress
(
debugLaunchProgressId
)
;
else
await
this
.
connectToVmServiceIfReady
(
)
;
this
.
sendEvent
(
new
Event
(
"flutter.appStarted"
)
)
;
}
)
;
this
.
runDaemon
.
registerForAppStop
(
(
n
)
=>
{
this
.
currentRunningAppId
=
undefined
;
if
(
this
.
runDaemon
)
{
this
.
runDaemon
.
dispose
(
)
;
this
.
runDaemon
=
undefined
;
}
}
)
;
this
.
runDaemon
.
registerForAppProgress
(
(
e
)
=>
{
if
(
!
this
.
appHasStarted
)
this
.
sendLaunchProgressEvent
(
e
)
;
else
this
.
sendProgressEvent
(
e
)
;
}
)
;
this
.
runDaemon
.
registerForAppWebLaunchUrl
(
(
e
)
=>
this
.
sendEvent
(
new
Event
(
"dart.webLaunchUrl"
,
{
url
:
e
.
url
,
launched
:
e
.
launched
}
)
)
)
;
// TODO: Should this use logToUser?
this
.
runDaemon
.
registerForError
(
(
err
)
=>
this
.
sendEvent
(
new
OutputEvent
(
`
${
err
}
\n`
,
"stderr"
)
)
)
;
this
.
runDaemon
.
registerForDaemonLog
(
(
msg
)
=>
this
.
handleLogOutput
(
msg
.
log
,
msg
.
error
)
)
;
this
.
runDaemon
.
registerForAppLog
(
(
msg
)
=>
this
.
handleLogOutput
(
msg
.
log
,
msg
.
error
)
)
;
return
this
.
runDaemon
.
process
!
;
}
private
sendLaunchProgressEvent
(
e
:
AppProgress
)
{
// We ignore finish progress events for launch progress because we use a
// single ID for launch progress to avoid multiple progress indicators and
// don't want to hide the overall progress when the first step completes.
//
// We'll hide the overall launch progress when we connect to the VM service.
if
(
!
e
.
finished
&&
e
.
message
)
this
.
updateProgress
(
debugLaunchProgressId
,
e
.
message
)
;
}
private
sendProgressEvent
(
e
:
AppProgress
)
{
const
progressId
=
`flutter-
${
e
.
appId
}
-
${
e
.
progressId
}
`
;
if
(
e
.
finished
)
{
let
finalMessage
:
string
|
undefined
;
if
(
!
finalMessage
)
{
if
(
e
.
progressId
===
"hot.reload"
)
finalMessage
=
"Hot Reload complete!"
;
else
if
(
e
.
progressId
===
"hot.restart"
)
finalMessage
=
"Hot Restart complete!"
;
}
this
.
endProgress
(
progressId
,
finalMessage
)
;
}
else
{
this
.
startProgress
(
progressId
,
e
.
message
)
;
}
}
private
handleLogOutput
(
msg
:
string
,
forceErrorCategory
=
false
)
{
msg
=
`
${
msg
.
trimRight
(
)
}
\n`
;
if
(
msg
.
includes
(
flutterExceptionStartBannerPrefix
)
)
{
// Change before logging.
this
.
outputCategory
=
"stderr"
;
this
.
logToUser
(
msg
,
this
.
outputCategory
)
;
}
else
if
(
msg
.
includes
(
flutterExceptionEndBannerPrefix
)
)
{
// Log before changing back.
this
.
logToUser
(
msg
,
this
.
outputCategory
)
;
this
.
outputCategory
=
"stdout"
;
}
else
{
this
.
logToUser
(
msg
,
forceErrorCategory
?
"stderr"
:
this
.
outputCategory
)
;
// This text comes through as stdout and not Progress, so map it over
// to progress indicator.
if
(
msg
.
includes
(
"Waiting for connection from"
)
)
{
const
instructions
=
"Please click the Dart Debug extension button in the spawned browser window"
;
this
.
updateProgress
(
debugLaunchProgressId
,
instructions
)
;
// Send this delayed, so it appears after the rest of the help text.
setTimeout
(
(
)
=>
this
.
logToUser
(
`
${
instructions
}
\n`
,
forceErrorCategory
?
"stderr"
:
this
.
outputCategory
)
,
10
)
;
}
}
}
private
async
connectToVmServiceIfReady
(
)
{
if
(
this
.
vmServiceUri
&&
this
.
appHasStarted
&&
!
this
.
vmService
)
await
this
.
initDebugger
(
this
.
vmServiceUri
)
;
}
protected
async
terminate
(
force
:
boolean
)
:
Promise
<
void
>
{
if
(
!
this
.
appHasBeenToldToStopOrDetach
)
{
this
.
appHasBeenToldToStopOrDetach
=
true
;
try
{
if
(
this
.
currentRunningAppId
&&
this
.
appHasStarted
&&
!
this
.
processExited
&&
this
.
runDaemon
)
{
// Request to quit/detach, but don't await it since we sometimes
// don't get responses before the process quits.
void
this
.
runDaemon
.
stop
(
this
.
currentRunningAppId
)
;
// Now wait for the process to terminate up to 3s.
await
Promise
.
race
(
[
this
.
processExit
,
new
Promise
(
(
resolve
)
=>
setTimeout
(
resolve
,
3000
)
)
,
]
)
;
}
}
catch
{
// Ignore failures here (we're shutting down and will send kill signals).
}
}
await
super
.
terminate
(
force
)
;
}
protected
async
restartRequest
(
response
:
DebugProtocol
.
RestartResponse
,
args
:
DebugProtocol
.
RestartArguments
,
)
:
Promise
<
void
>
{
this
.
sendEvent
(
new
Event
(
"dart.hotRestartRequest"
)
)
;
this
.
sendEvent
(
new
ContinuedEvent
(
0
,
true
)
)
;
this
.
reloadPackageMap
(
)
;
await
this
.
performReload
(
true
,
{
reason
:
restartReasonManual
}
)
;
super
.
restartRequest
(
response
,
args
)
;
}
private
reloadPackageMap
(
)
:
void
{
// Reload the package map in case the user modified the packages.
// https://github.com/Dart-Code/Dart-Code/issues/4076.
this
.
packageMap
?.
reload
(
)
;
}
private
async
performReload
(
hotRestart
:
boolean
,
args
?:
{
reason
:
string
,
debounce
?:
boolean
}
)
:
Promise
<
any
>
{
if
(
!
this
.
appHasStarted
||
!
this
.
currentRunningAppId
||
!
this
.
runDaemon
)
return
;
const
restartType
=
hotRestart
?
"hot-restart"
:
"hot-reload"
;
// To avoid issues with hot restart pausing on exceptions during the restart, we remove
// exception-pause behaviour here, and it will be re-added as part of the startup code
// when the new isolate appears.
if
(
hotRestart
)
await
this
.
threadManager
.
setExceptionPauseMode
(
"None"
,
false
)
;
try
{
await
this
.
runDaemon
.
restart
(
this
.
currentRunningAppId
,
!
this
.
noDebug
,
hotRestart
,
args
)
;
}
catch
(
e
)
{
this
.
sendEvent
(
new
OutputEvent
(
`Error running
${
restartType
}
:
${
e
}
\n`
,
"stderr"
)
)
;
}
}
protected
async
customRequest
(
request
:
string
,
response
:
DebugProtocol
.
Response
,
args
:
any
)
:
Promise
<
void
>
{
try
{
switch
(
request
)
{
case
"hotReload"
:
if
(
this
.
currentRunningAppId
)
await
this
.
performReload
(
false
,
args
as
{
reason
:
string
,
debounce
?:
boolean
}
)
;
this
.
sendResponse
(
response
)
;
break
;
case
"hotRestart"
:
if
(
this
.
currentRunningAppId
)
{
this
.
reloadPackageMap
(
)
;
await
this
.
performReload
(
true
,
args
as
{
reason
:
string
,
debounce
?:
boolean
}
)
;
}
this
.
sendResponse
(
response
)
;
break
;
default
:
await
super
.
customRequest
(
request
,
response
,
args
)
;
break
;
}
}
catch
(
e
:
any
)
{
const
error
=
errorString
(
e
)
;
const
message
=
`Error handling '
${
request
}
' custom request:
${
error
}
`
;
if
(
!
this
.
isTerminating
)
this
.
sendEvent
(
new
OutputEvent
(
`
${
message
}
\n`
,
"stderr"
)
)
;
this
.
logger
.
error
(
message
)
;
this
.
errorResponse
(
response
,
message
)
;
}
}
protected
async
handleInspectEvent
(
event
:
VMEvent
)
:
Promise
<
void
>
{
if
(
!
this
.
runDaemon
||
!
this
.
currentRunningAppId
)
return
;
const
selectedWidget
=
await
this
.
runDaemon
.
callServiceExtension
(
this
.
currentRunningAppId
,
"ext.flutter.inspector.getSelectedSummaryWidget"
,
{
previousSelectionId
:
null
,
objectGroup
:
objectGroupName
}
,
)
;
try
{
if
(
selectedWidget
&&
selectedWidget
.
result
&&
selectedWidget
.
result
.
creationLocation
)
{
const
loc
=
selectedWidget
.
result
.
creationLocation
;
const
file
=
loc
.
file
;
const
line
=
loc
.
line
;
const
column
=
loc
.
column
;
this
.
sendEvent
(
new
Event
(
"dart.navigate"
,
{
file
,
line
,
column
,
inOtherEditorColumn
:
true
,
fromInspector
:
true
}
)
)
;
}
else
{
await
super
.
handleInspectEvent
(
event
)
;
}
}
finally
{
await
this
.
runDaemon
.
callServiceExtension
(
this
.
currentRunningAppId
,
"ext.flutter.inspector.disposeGroup"
,
{
objectGroup
:
objectGroupName
}
,
)
;
}
}
protected
async
attachRequest
(
_response
:
DebugProtocol
.
AttachResponse
,
args
:
DartLaunchArgs
)
:
Promise
<
void
>
{
this
.
logToUser
(
"Attach is not supported for Dart web projects\n"
)
;
this
.
sendEvent
(
new
TerminatedEvent
(
)
)
;
}
protected
spawnRunDaemon
(
args
:
DartLaunchArgs
,
logger
:
Logger
)
:
WebRun
{
let
allArgs
:
string
[
]
=
[
"global"
,
"run"
,
"webdev"
,
"daemon"
]
;
// if (this.shouldConnectDebugger) {
// appArgs.push("--start-paused");
// }
// }
if
(
args
.
toolArgs
)
allArgs
=
allArgs
.
concat
(
args
.
toolArgs
)
;
const
pubExecution
=
getPubExecutionInfo
(
this
.
dartCapabilities
,
args
.
dartSdkPath
,
allArgs
,
)
;
const
customTool
=
{
replacesArgs
:
args
.
customToolReplacesArgs
,
script
:
args
.
customTool
,
}
;
let
execution
=
usingCustomScript
(
pubExecution
.
executable
,
pubExecution
.
args
,
customTool
,
)
;
allArgs
=
execution
.
args
;
if
(
args
.
args
)
allArgs
=
allArgs
.
concat
(
args
.
args
)
;
execution
=
{
args
:
allArgs
,
executable
:
execution
.
executable
,
}
;
// TODO: Attach?
return
new
WebRun
(
this
.
dartCapabilities
,
execution
,
args
.
cwd
,
{
envOverrides
:
args
.
env
,
toolEnv
:
this
.
toolEnv
}
,
args
.
webDaemonLogFile
,
logger
,
(
url
)
=>
this
.
exposeUrl
(
url
)
,
this
.
maxLogLineLength
)
;
}
}
Back
|
FazBrowse Home
|
New Git URL