• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3#
4# Copyright (c) 2024-2025 Huawei Device Co., Ltd.
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17
18from collections.abc import Sequence
19from pathlib import Path
20from typing import Iterable, List, Set
21
22import trio
23from rich import box
24from rich.columns import Columns
25from rich.console import Group, RenderableType
26from rich.panel import Panel
27from rich.pretty import Pretty
28from rich.syntax import Syntax
29from rich.table import Column, Table
30from rich.text import Text
31
32from .debug_types import DEFAULT_DEPTH, Frame, Paused, Scope
33
34
35def source_file(src_file: Path, **kwargs) -> Syntax:
36    return Syntax.from_path(
37        path=str(src_file),
38        lexer="ts",
39        start_line=0,
40        line_numbers=True,
41        **kwargs,
42    )
43
44
45async def _add_rows(table: Table, scope: Scope):
46    table.add_row(
47        f":red_triangle_pointed_down: [table.header]{scope.data.type_}[/table.header]",
48        Text(f"{scope.data.object_.description}", style="repr.str"),
49    )
50    props = await scope.mirror_variables()
51    if len(props):
52        for k, v in props.items():
53            table.add_row(k, Pretty(v))
54    else:
55        table.add_row("none", "", style="italic")
56
57
58async def frame_layout(
59    frame: Frame,
60    scopes: Set[str] | None = None,
61    skip_scopes: Sequence[str] | None = None,
62) -> RenderableType:
63    table = Table(
64        Column("name"),
65        Column("value"),
66        box=box.SIMPLE,
67        show_edge=False,
68    )
69    this = frame.this()
70    if this is not None:
71        table.add_row("this", Pretty(await this.mirror_value(depth=DEFAULT_DEPTH)))
72    else:
73        await trio.lowlevel.checkpoint()
74    # NOTE(dslynko, #22497): now global scope is ignored by default, because it enumerates all classes from boot.
75    # Need to enable enumerating globals after debugger server enumerates only non-boot classes.
76    skip_scopes = skip_scopes if skip_scopes is not None else ("global",)
77    for scope in frame.scopes():
78        if (scopes is None or scope.data.type_ in scopes) and (scope.data.type_ not in skip_scopes):
79            await _add_rows(table, scope)
80        else:
81            table.add_row(
82                f":red_triangle_pointed_up: [table.header]{scope.data.type_}[/table.header]",
83                f"[repr.str]{scope.data.object_.description}[/repr.str]",
84            )
85
86    title = "[inspect.class]%s[/inspect.class] [repr.filename]%s[/repr.filename]:[repr.number]%s[/repr.number]" % (
87        frame.data.function_name,
88        Path(frame.data.url).name,
89        frame.data.location.line_number,
90    )
91    return Panel(table, title=title, title_align="left")
92
93
94async def frames_layout(
95    call_frames: Iterable[Frame],
96    scopes: Set[str] | None = None,
97    skip_scopes: Sequence[str] | None = None,
98) -> List[RenderableType]:
99
100    await trio.lowlevel.checkpoint()
101    return [await frame_layout(f, scopes, skip_scopes) for f in call_frames]
102
103
104async def paused_layout(
105    paused: Paused,
106    url: Path,
107    scopes: Set[str] | None = None,
108    skip_scopes: Sequence[str] | None = None,
109) -> RenderableType:
110    frames = await frames_layout(paused.frames(), scopes=scopes, skip_scopes=skip_scopes)
111    highlight_lines = [f.location.line_number for f in paused.data.call_frames]
112    code = source_file(url, highlight_lines=highlight_lines)
113    return Columns([code, Group(*frames)])
114