| 727 | } |
| 728 | |
| 729 | private async convertStackFrame(thread: ThreadInfo, frame: VMFrame, isTopFrame: boolean, hasDebuggableFrames: boolean, firstAsyncMarkerIndex: number): Promise<DebugProtocol.StackFrame> { |
| 730 | const frameId = thread.storeData(frame); |
| 731 | |
| 732 | if (frame.kind === "AsyncSuspensionMarker") { |
| 733 | const stackFrame: DebugProtocol.StackFrame = new StackFrame(frameId, "<asynchronous gap>"); |
| 734 | stackFrame.presentationHint = "label"; |
| 735 | return stackFrame; |
| 736 | } |
| 737 | |
| 738 | const frameName = |
| 739 | frame && frame.code && frame.code.name |
| 740 | ? ( |
| 741 | frame.code.name.startsWith(unoptimizedPrefix) |
| 742 | ? frame.code.name.substring(unoptimizedPrefix.length) |
| 743 | : frame.code.name |
| 744 | ) |
| 745 | : "<unknown>"; |
| 746 | const location = frame.location; |
| 747 | |
| 748 | if (!location) { |
| 749 | const stackFrame: DebugProtocol.StackFrame = new StackFrame(frameId, frameName); |
| 750 | stackFrame.presentationHint = "subtle"; |
| 751 | return stackFrame; |
| 752 | } |
| 753 | |
| 754 | const uri = location.script.uri; |
| 755 | let sourcePath = this.convertVMUriToSourcePath(uri); |
| 756 | let canShowSource = sourcePath && fs.existsSync(sourcePath); |
| 757 | |
| 758 | // Download the source if from a "dart:" uri. |
| 759 | let sourceReference: number | undefined; |
| 760 | if (uri.startsWith("dart:") || uri.startsWith("org-dartlang-app:")) { |
| 761 | sourcePath = undefined; |
| 762 | sourceReference = thread.storeData(location.script); |
| 763 | canShowSource = true; |
| 764 | } |
| 765 | |
| 766 | const shortName = this.formatUriForShortDisplay(uri); |
| 767 | const stackFrame: DebugProtocol.StackFrame = new StackFrame( |
| 768 | frameId, |
| 769 | frameName, |
| 770 | canShowSource ? new Source(shortName, sourcePath, sourceReference, undefined, location.script) : undefined, |
| 771 | 0, 0, |
| 772 | ); |
| 773 | // The top frame is only allowed to be deemphasized when it's an exception and there is some user-code in the |
| 774 | // stack (so the editor can walk up the stack to user code). |
| 775 | // If the reason for stopping was a breakpoint, step, etc., then we should always leave the frame focusable. |
| 776 | const isStoppedAtException = thread.exceptionReference !== 0; |
| 777 | const allowDeemphasizingFrame = !isTopFrame || (isStoppedAtException && hasDebuggableFrames); |
| 778 | |
| 779 | // If we wouldn't debug this source, then deemphasize in the stack. |
| 780 | if (stackFrame.source) { |
| 781 | if (this.isSdkLibrary(uri)) |
| 782 | stackFrame.source.origin = "from the SDK"; |
| 783 | else if (this.isExternalLibrary(uri)) |
| 784 | stackFrame.source.origin = uri.startsWith("package:flutter/") ? "from the Flutter framework" : "from external packages"; |
| 785 | |
| 786 | if (allowDeemphasizingFrame && !this.isDebuggable(uri)) |