|
8 | 8 |
|
9 | 9 | #include "DAP.h" |
10 | 10 | #include "JSONUtils.h" |
| 11 | +#include "Protocol/ProtocolRequests.h" |
| 12 | +#include "Protocol/ProtocolTypes.h" |
11 | 13 | #include "RequestHandler.h" |
12 | 14 | #include "lldb/API/SBStringList.h" |
13 | 15 |
|
14 | | -namespace lldb_dap { |
| 16 | +using namespace llvm; |
| 17 | +using namespace lldb_dap; |
| 18 | +using namespace lldb_dap::protocol; |
15 | 19 |
|
16 | | -// "CompletionsRequest": { |
17 | | -// "allOf": [ { "$ref": "#/definitions/Request" }, { |
18 | | -// "type": "object", |
19 | | -// "description": "Returns a list of possible completions for a given caret |
20 | | -// position and text.\nThe CompletionsRequest may only be called if the |
21 | | -// 'supportsCompletionsRequest' capability exists and is true.", |
22 | | -// "properties": { |
23 | | -// "command": { |
24 | | -// "type": "string", |
25 | | -// "enum": [ "completions" ] |
26 | | -// }, |
27 | | -// "arguments": { |
28 | | -// "$ref": "#/definitions/CompletionsArguments" |
29 | | -// } |
30 | | -// }, |
31 | | -// "required": [ "command", "arguments" ] |
32 | | -// }] |
33 | | -// }, |
34 | | -// "CompletionsArguments": { |
35 | | -// "type": "object", |
36 | | -// "description": "Arguments for 'completions' request.", |
37 | | -// "properties": { |
38 | | -// "frameId": { |
39 | | -// "type": "integer", |
40 | | -// "description": "Returns completions in the scope of this stack frame. |
41 | | -// If not specified, the completions are returned for the global scope." |
42 | | -// }, |
43 | | -// "text": { |
44 | | -// "type": "string", |
45 | | -// "description": "One or more source lines. Typically this is the text a |
46 | | -// user has typed into the debug console before he asked for completion." |
47 | | -// }, |
48 | | -// "column": { |
49 | | -// "type": "integer", |
50 | | -// "description": "The character position for which to determine the |
51 | | -// completion proposals." |
52 | | -// }, |
53 | | -// "line": { |
54 | | -// "type": "integer", |
55 | | -// "description": "An optional line for which to determine the completion |
56 | | -// proposals. If missing the first line of the text is assumed." |
57 | | -// } |
58 | | -// }, |
59 | | -// "required": [ "text", "column" ] |
60 | | -// }, |
61 | | -// "CompletionsResponse": { |
62 | | -// "allOf": [ { "$ref": "#/definitions/Response" }, { |
63 | | -// "type": "object", |
64 | | -// "description": "Response to 'completions' request.", |
65 | | -// "properties": { |
66 | | -// "body": { |
67 | | -// "type": "object", |
68 | | -// "properties": { |
69 | | -// "targets": { |
70 | | -// "type": "array", |
71 | | -// "items": { |
72 | | -// "$ref": "#/definitions/CompletionItem" |
73 | | -// }, |
74 | | -// "description": "The possible completions for ." |
75 | | -// } |
76 | | -// }, |
77 | | -// "required": [ "targets" ] |
78 | | -// } |
79 | | -// }, |
80 | | -// "required": [ "body" ] |
81 | | -// }] |
82 | | -// }, |
83 | | -// "CompletionItem": { |
84 | | -// "type": "object", |
85 | | -// "description": "CompletionItems are the suggestions returned from the |
86 | | -// CompletionsRequest.", "properties": { |
87 | | -// "label": { |
88 | | -// "type": "string", |
89 | | -// "description": "The label of this completion item. By default this is |
90 | | -// also the text that is inserted when selecting this completion." |
91 | | -// }, |
92 | | -// "text": { |
93 | | -// "type": "string", |
94 | | -// "description": "If text is not falsy then it is inserted instead of the |
95 | | -// label." |
96 | | -// }, |
97 | | -// "sortText": { |
98 | | -// "type": "string", |
99 | | -// "description": "A string that should be used when comparing this item |
100 | | -// with other items. When `falsy` the label is used." |
101 | | -// }, |
102 | | -// "type": { |
103 | | -// "$ref": "#/definitions/CompletionItemType", |
104 | | -// "description": "The item's type. Typically the client uses this |
105 | | -// information to render the item in the UI with an icon." |
106 | | -// }, |
107 | | -// "start": { |
108 | | -// "type": "integer", |
109 | | -// "description": "This value determines the location (in the |
110 | | -// CompletionsRequest's 'text' attribute) where the completion text is |
111 | | -// added.\nIf missing the text is added at the location specified by the |
112 | | -// CompletionsRequest's 'column' attribute." |
113 | | -// }, |
114 | | -// "length": { |
115 | | -// "type": "integer", |
116 | | -// "description": "This value determines how many characters are |
117 | | -// overwritten by the completion text.\nIf missing the value 0 is assumed |
118 | | -// which results in the completion text being inserted." |
119 | | -// } |
120 | | -// }, |
121 | | -// "required": [ "label" ] |
122 | | -// }, |
123 | | -// "CompletionItemType": { |
124 | | -// "type": "string", |
125 | | -// "description": "Some predefined types for the CompletionItem. Please note |
126 | | -// that not all clients have specific icons for all of them.", "enum": [ |
127 | | -// "method", "function", "constructor", "field", "variable", "class", |
128 | | -// "interface", "module", "property", "unit", "value", "enum", "keyword", |
129 | | -// "snippet", "text", "color", "file", "reference", "customcolor" ] |
130 | | -// } |
131 | | -void CompletionsRequestHandler::operator()( |
132 | | - const llvm::json::Object &request) const { |
133 | | - llvm::json::Object response; |
134 | | - FillResponse(request, response); |
135 | | - llvm::json::Object body; |
136 | | - const auto *arguments = request.getObject("arguments"); |
| 20 | +namespace lldb_dap { |
137 | 21 |
|
| 22 | +/// Returns a list of possible completions for a given caret position and text. |
| 23 | +/// |
| 24 | +/// Clients should only call this request if the corresponding capability |
| 25 | +/// `supportsCompletionsRequest` is true. |
| 26 | +Expected<CompletionsResponseBody> |
| 27 | +CompletionsRequestHandler::Run(const CompletionsArguments &args) const { |
138 | 28 | // If we have a frame, try to set the context for variable completions. |
139 | | - lldb::SBFrame frame = dap.GetLLDBFrame(*arguments); |
| 29 | + lldb::SBFrame frame = dap.GetLLDBFrame(args.frameId); |
140 | 30 | if (frame.IsValid()) { |
141 | 31 | frame.GetThread().GetProcess().SetSelectedThread(frame.GetThread()); |
142 | 32 | frame.GetThread().SetSelectedFrame(frame.GetFrameID()); |
143 | 33 | } |
144 | 34 |
|
145 | | - std::string text = GetString(arguments, "text").value_or("").str(); |
146 | | - auto original_column = |
147 | | - GetInteger<int64_t>(arguments, "column").value_or(text.size()); |
148 | | - auto original_line = GetInteger<int64_t>(arguments, "line").value_or(1); |
| 35 | + std::string text = args.text; |
| 36 | + auto original_column = args.column; |
| 37 | + auto original_line = args.line; |
149 | 38 | auto offset = original_column - 1; |
150 | 39 | if (original_line > 1) { |
151 | | - llvm::SmallVector<::llvm::StringRef, 2> lines; |
152 | | - llvm::StringRef(text).split(lines, '\n'); |
| 40 | + SmallVector<StringRef, 2> lines; |
| 41 | + StringRef(text).split(lines, '\n'); |
153 | 42 | for (int i = 0; i < original_line - 1; i++) { |
154 | 43 | offset += lines[i].size(); |
155 | 44 | } |
156 | 45 | } |
157 | | - llvm::json::Array targets; |
| 46 | + |
| 47 | + std::vector<CompletionItem> targets; |
158 | 48 |
|
159 | 49 | bool had_escape_prefix = |
160 | | - llvm::StringRef(text).starts_with(dap.configuration.commandEscapePrefix); |
| 50 | + StringRef(text).starts_with(dap.configuration.commandEscapePrefix); |
161 | 51 | ReplMode completion_mode = dap.DetectReplMode(frame, text, true); |
162 | 52 |
|
163 | 53 | // Handle the offset change introduced by stripping out the |
164 | 54 | // `command_escape_prefix`. |
165 | 55 | if (had_escape_prefix) { |
166 | 56 | if (offset < |
167 | 57 | static_cast<int64_t>(dap.configuration.commandEscapePrefix.size())) { |
168 | | - body.try_emplace("targets", std::move(targets)); |
169 | | - response.try_emplace("body", std::move(body)); |
170 | | - dap.SendJSON(llvm::json::Value(std::move(response))); |
171 | | - return; |
| 58 | + return CompletionsResponseBody{std::move(targets)}; |
172 | 59 | } |
173 | 60 | offset -= dap.configuration.commandEscapePrefix.size(); |
174 | 61 | } |
@@ -198,27 +85,25 @@ void CompletionsRequestHandler::operator()( |
198 | 85 | std::string match = matches.GetStringAtIndex(i); |
199 | 86 | std::string description = descriptions.GetStringAtIndex(i); |
200 | 87 |
|
201 | | - llvm::json::Object item; |
202 | | - llvm::StringRef match_ref = match; |
203 | | - for (llvm::StringRef commit_point : {".", "->"}) { |
| 88 | + CompletionItem item; |
| 89 | + StringRef match_ref = match; |
| 90 | + for (StringRef commit_point : {".", "->"}) { |
204 | 91 | if (match_ref.contains(commit_point)) { |
205 | 92 | match_ref = match_ref.rsplit(commit_point).second; |
206 | 93 | } |
207 | 94 | } |
208 | | - EmplaceSafeString(item, "text", match_ref); |
| 95 | + item.text = match_ref; |
209 | 96 |
|
210 | 97 | if (description.empty()) |
211 | | - EmplaceSafeString(item, "label", match); |
| 98 | + item.label = match; |
212 | 99 | else |
213 | | - EmplaceSafeString(item, "label", match + " -- " + description); |
| 100 | + item.label = match + " -- " + description; |
214 | 101 |
|
215 | 102 | targets.emplace_back(std::move(item)); |
216 | 103 | } |
217 | 104 | } |
218 | 105 |
|
219 | | - body.try_emplace("targets", std::move(targets)); |
220 | | - response.try_emplace("body", std::move(body)); |
221 | | - dap.SendJSON(llvm::json::Value(std::move(response))); |
| 106 | + return CompletionsResponseBody{std::move(targets)}; |
222 | 107 | } |
223 | 108 |
|
224 | 109 | } // namespace lldb_dap |
0 commit comments