Skip to content

Commit 3db3a71

Browse files
committed
[lldb-dap] Migrating 'completions' to structured types.
This migrates the CompletionHandler to structured types and adds a new CompletionItem and CompletionItemType to the general types.
1 parent 3589234 commit 3db3a71

File tree

6 files changed

+272
-147
lines changed

6 files changed

+272
-147
lines changed

lldb/tools/lldb-dap/Handler/CompletionsHandler.cpp

Lines changed: 31 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -8,167 +8,54 @@
88

99
#include "DAP.h"
1010
#include "JSONUtils.h"
11+
#include "Protocol/ProtocolRequests.h"
12+
#include "Protocol/ProtocolTypes.h"
1113
#include "RequestHandler.h"
1214
#include "lldb/API/SBStringList.h"
1315

14-
namespace lldb_dap {
16+
using namespace llvm;
17+
using namespace lldb_dap;
18+
using namespace lldb_dap::protocol;
1519

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 {
13721

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 {
13828
// 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);
14030
if (frame.IsValid()) {
14131
frame.GetThread().GetProcess().SetSelectedThread(frame.GetThread());
14232
frame.GetThread().SetSelectedFrame(frame.GetFrameID());
14333
}
14434

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;
14938
auto offset = original_column - 1;
15039
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');
15342
for (int i = 0; i < original_line - 1; i++) {
15443
offset += lines[i].size();
15544
}
15645
}
157-
llvm::json::Array targets;
46+
47+
std::vector<CompletionItem> targets;
15848

15949
bool had_escape_prefix =
160-
llvm::StringRef(text).starts_with(dap.configuration.commandEscapePrefix);
50+
StringRef(text).starts_with(dap.configuration.commandEscapePrefix);
16151
ReplMode completion_mode = dap.DetectReplMode(frame, text, true);
16252

16353
// Handle the offset change introduced by stripping out the
16454
// `command_escape_prefix`.
16555
if (had_escape_prefix) {
16656
if (offset <
16757
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{targets};
17259
}
17360
offset -= dap.configuration.commandEscapePrefix.size();
17461
}
@@ -198,27 +85,27 @@ void CompletionsRequestHandler::operator()(
19885
std::string match = matches.GetStringAtIndex(i);
19986
std::string description = descriptions.GetStringAtIndex(i);
20087

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 : {".", "->"}) {
20491
if (match_ref.contains(commit_point)) {
20592
match_ref = match_ref.rsplit(commit_point).second;
20693
}
20794
}
208-
EmplaceSafeString(item, "text", match_ref);
95+
item.text = match_ref;
20996

21097
if (description.empty())
211-
EmplaceSafeString(item, "label", match);
98+
item.label = match;
21299
else
213-
EmplaceSafeString(item, "label", match + " -- " + description);
100+
item.label = match + " -- " + description;
214101

215102
targets.emplace_back(std::move(item));
216103
}
217104
}
218105

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+
CompletionsResponseBody body;
107+
body.targets = std::move(targets);
108+
return body;
222109
}
223110

224111
} // namespace lldb_dap

lldb/tools/lldb-dap/Handler/RequestHandler.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -243,14 +243,17 @@ class BreakpointLocationsRequestHandler
243243
uint32_t end_line) const;
244244
};
245245

246-
class CompletionsRequestHandler : public LegacyRequestHandler {
246+
class CompletionsRequestHandler
247+
: public RequestHandler<protocol::CompletionsArguments,
248+
llvm::Expected<protocol::CompletionsResponseBody>> {
247249
public:
248-
using LegacyRequestHandler::LegacyRequestHandler;
250+
using RequestHandler::RequestHandler;
249251
static llvm::StringLiteral GetCommand() { return "completions"; }
250252
FeatureSet GetSupportedFeatures() const override {
251253
return {protocol::eAdapterFeatureCompletionsRequest};
252254
}
253-
void operator()(const llvm::json::Object &request) const override;
255+
llvm::Expected<protocol::CompletionsResponseBody>
256+
Run(const protocol::CompletionsArguments &args) const override;
254257
};
255258

256259
class ContinueRequestHandler

lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,17 @@ json::Value toJSON(const ContinueResponseBody &CRB) {
329329
return std::move(Body);
330330
}
331331

332+
bool fromJSON(const json::Value &Params, CompletionsArguments &CA,
333+
json::Path P) {
334+
json::ObjectMapper O(Params, P);
335+
return O && O.map("text", CA.text) && O.map("column", CA.column) &&
336+
O.mapOptional("frameId", CA.frameId) && O.mapOptional("line", CA.line);
337+
}
338+
339+
json::Value toJSON(const CompletionsResponseBody &CRB) {
340+
return json::Object{{"targets", CRB.targets}};
341+
}
342+
332343
bool fromJSON(const json::Value &Params, SetVariableArguments &SVA,
333344
json::Path P) {
334345
json::ObjectMapper O(Params, P);

lldb/tools/lldb-dap/Protocol/ProtocolRequests.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,35 @@ struct ContinueResponseBody {
376376
};
377377
llvm::json::Value toJSON(const ContinueResponseBody &);
378378

379+
/// Arguments for `completions` request.
380+
struct CompletionsArguments {
381+
/// Returns completions in the scope of this stack frame. If not specified,
382+
/// the completions are returned for the global scope.
383+
uint64_t frameId = LLDB_INVALID_FRAME_ID;
384+
385+
/// One or more source lines. Typically this is the text users have typed into
386+
/// the debug console before they asked for completion.
387+
std::string text;
388+
389+
/// The position within `text` for which to determine the completion
390+
/// proposals. It is measured in UTF-16 code units and the client capability
391+
/// `columnsStartAt1` determines whether it is 0- or 1-based.
392+
int64_t column = 0;
393+
394+
/// A line for which to determine the completion proposals. If missing the
395+
/// first line of the text is assumed.
396+
int64_t line = 0;
397+
};
398+
bool fromJSON(const llvm::json::Value &, CompletionsArguments &,
399+
llvm::json::Path);
400+
401+
/// Response to `completions` request.
402+
struct CompletionsResponseBody {
403+
/// The possible completions for a given caret position and text.
404+
std::vector<CompletionItem> targets;
405+
};
406+
llvm::json::Value toJSON(const CompletionsResponseBody &);
407+
379408
/// Arguments for `configurationDone` request.
380409
using ConfigurationDoneArguments = EmptyArguments;
381410

0 commit comments

Comments
 (0)