]>
Commit | Line | Data |
---|---|---|
d01e8234 | 1 | # Copyright 2023-2025 Free Software Foundation, Inc. |
a0b70d99 TT |
2 | |
3 | # This program is free software; you can redistribute it and/or modify | |
4 | # it under the terms of the GNU General Public License as published by | |
5 | # the Free Software Foundation; either version 3 of the License, or | |
6 | # (at your option) any later version. | |
7 | # | |
8 | # This program is distributed in the hope that it will be useful, | |
9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | # GNU General Public License for more details. | |
12 | # | |
13 | # You should have received a copy of the GNU General Public License | |
14 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
15 | ||
0b7de6d3 GA |
16 | import os |
17 | ||
c2cf30e7 | 18 | from .server import capability, request |
0341f276 | 19 | from .startup import DAPException, exec_mi_and_log, in_gdb_thread |
a0b70d99 | 20 | |
c64cba1b TT |
21 | # The next available source reference ID. Must be greater than 0. |
22 | _next_source = 1 | |
23 | ||
24 | # Map from full paths to Source dictionaries. | |
25 | _source_map = {} | |
26 | ||
27 | # Map from a source reference ID back to the same Source that is | |
28 | # stored in _source_map. | |
29 | _id_map = {} | |
30 | ||
31 | ||
32 | @in_gdb_thread | |
4b09134a | 33 | def make_source(fullname, filename=None): |
c64cba1b TT |
34 | """Return the Source for a given file name. |
35 | ||
36 | FULLNAME is the full name. This is used as the key. | |
4b09134a TT |
37 | FILENAME is the base name; if None (the default), then it is |
38 | computed from FULLNAME. | |
c64cba1b | 39 | """ |
c64cba1b TT |
40 | if fullname in _source_map: |
41 | result = _source_map[fullname] | |
42 | else: | |
4b09134a TT |
43 | if filename is None: |
44 | filename = os.path.basename(fullname) | |
45 | ||
c64cba1b TT |
46 | result = { |
47 | "name": filename, | |
48 | "path": fullname, | |
c64cba1b | 49 | } |
0b7de6d3 GA |
50 | |
51 | if not os.path.exists(fullname): | |
52 | global _next_source | |
53 | result["sourceReference"] = _next_source | |
54 | ||
0b7de6d3 GA |
55 | _id_map[_next_source] = result |
56 | _next_source += 1 | |
57 | ||
c64cba1b | 58 | _source_map[fullname] = result |
c64cba1b TT |
59 | return result |
60 | ||
61 | ||
4b6521cf TT |
62 | @in_gdb_thread |
63 | def decode_source(source): | |
64 | """Decode a Source object. | |
65 | ||
66 | Finds and returns the filename of a given Source object.""" | |
b33b677b | 67 | if "sourceReference" not in source or source["sourceReference"] <= 0: |
68 | if "path" in source: | |
69 | return source["path"] | |
2a89c950 | 70 | raise DAPException("either 'path' or 'sourceReference' must appear in Source") |
4b6521cf | 71 | ref = source["sourceReference"] |
4b6521cf | 72 | if ref not in _id_map: |
2a89c950 | 73 | raise DAPException("no sourceReference " + str(ref)) |
4b6521cf TT |
74 | return _id_map[ref]["path"] |
75 | ||
76 | ||
c98921b2 TT |
77 | @request("loadedSources") |
78 | @capability("supportsLoadedSourcesRequest") | |
79 | def loaded_sources(**extra): | |
a0b70d99 | 80 | result = [] |
0341f276 | 81 | for elt in exec_mi_and_log("-file-list-exec-source-files")["files"]: |
c64cba1b | 82 | result.append(make_source(elt["fullname"], elt["file"])) |
a0b70d99 TT |
83 | return { |
84 | "sources": result, | |
85 | } | |
86 | ||
87 | ||
13bd1a91 TT |
88 | @request("source") |
89 | def source(*, source=None, sourceReference: int, **extra): | |
90 | # The 'sourceReference' parameter is required by the spec, but is | |
91 | # for backward compatibility, which I take to mean that the | |
92 | # 'source' is preferred. | |
93 | if source is None: | |
94 | source = {"sourceReference": sourceReference} | |
c98921b2 TT |
95 | filename = decode_source(source) |
96 | with open(filename) as f: | |
97 | content = f.read() | |
98 | return { | |
99 | "content": content, | |
100 | } |