1import atexit
2import os.path
3import subprocess
4from tkinter import messagebox
5
6from thonny import THONNY_USER_DIR, get_runner, get_workbench, running
7from thonny.languages import tr
8
9_server_started = False
10_server_process = None
11
12
13def _start_debug_enabled():
14    return (
15        get_workbench().get_editor_notebook().get_current_editor() is not None
16        and "debug" in get_runner().get_supported_features()
17    )
18
19
20def start_server():
21    global _server_process
22
23    out_err_filename = os.path.join(THONNY_USER_DIR, "birdseye.log")
24    output_file = open(out_err_filename, "w")
25    _server_process = subprocess.Popen(
26        [
27            running.get_interpreter_for_subprocess(),
28            "-m",
29            "birdseye",
30            "-p",
31            str(get_workbench().get_option("run.birdseye_port")),
32        ],
33        stdout=output_file,
34        stderr=output_file,
35    )
36    atexit.register(close_server)
37
38
39def close_server():
40    if _server_process is not None:
41        try:
42            _server_process.kill()
43        except Exception:
44            pass
45
46
47def debug_with_birdseye():
48    global _server_started
49
50    try:
51        import birdseye  # @UnusedImport
52    except ImportError:
53        if messagebox.askyesno(
54            tr("About Birdseye"),
55            tr(
56                "Birdseye is a Python debugger which needs to be installed separately.\n\n"
57                + "Do you want to open the help page and learn more?"
58            ),
59            master=get_workbench(),
60        ):
61            get_workbench().open_help_topic("birdseye")
62
63        return
64
65    if not _server_started:
66        start_server()
67        _server_started = True
68
69    os.environ["BIRDSEYE_PORT"] = str(get_workbench().get_option("run.birdseye_port"))
70    get_runner().execute_current("Birdseye")
71
72
73# order_key makes the plugin to be loaded later than other same tier plugins
74# This way it gets positioned after main debug commands in the Run menu
75load_order_key = "zz"
76
77
78def load_plugin():
79    get_workbench().set_default("run.birdseye_port", 7777)
80    get_workbench().add_command(
81        "birdseye",
82        "run",
83        tr("Debug current script (birdseye)"),
84        debug_with_birdseye,
85        caption="birdseye",
86        tester=_start_debug_enabled,
87        default_sequence="<Control-B>",
88        group=10,
89        image=os.path.join(os.path.dirname(__file__), "..", "res", "birdseye.png"),
90    )
91