nixd
Loading...
Searching...
No Matches
CodeAction.cpp
Go to the documentation of this file.
1/// \file
2/// \brief Implementation of [Code Action].
3/// [Code Action]:
4/// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_codeAction
5
6#include "CheckReturn.h"
7#include "Convert.h"
8
19
21
22#include <boost/asio/post.hpp>
23#include <llvm/Support/JSON.h>
24
25namespace nixd {
26
27using namespace llvm::json;
28using namespace lspserver;
29
30void Controller::onCodeAction(const lspserver::CodeActionParams &Params,
31 Callback<std::vector<CodeAction>> Reply) {
32 using CheckTy = std::vector<CodeAction>;
33 std::string File(Params.textDocument.uri.file());
34 Range Range = Params.range;
35 auto Action = [Reply = std::move(Reply), File, Range, this]() mutable {
36 return Reply([&]() -> llvm::Expected<CheckTy> {
37 const auto TU = CheckDefault(getTU(File));
38
39 const auto &Diagnostics = TU->diagnostics();
40 auto Actions = std::vector<CodeAction>();
41 Actions.reserve(Diagnostics.size());
42 std::string FileURI = URIForFile::canonicalize(File, File).uri();
43
44 for (const nixf::Diagnostic &D : Diagnostics) {
45 auto DRange = toLSPRange(TU->src(), D.range());
46 if (!Range.overlap(DRange))
47 continue;
48
49 // Add fixes.
50 for (const nixf::Fix &F : D.fixes()) {
51 std::vector<TextEdit> Edits;
52 Edits.reserve(F.edits().size());
53 for (const nixf::TextEdit &TE : F.edits()) {
54 Edits.emplace_back(TextEdit{
55 .range = toLSPRange(TU->src(), TE.oldRange()),
56 .newText = std::string(TE.newText()),
57 });
58 }
59 using Changes = std::map<std::string, std::vector<TextEdit>>;
60 WorkspaceEdit WE{.changes = Changes{
61 {FileURI, std::move(Edits)},
62 }};
63 Actions.emplace_back(CodeAction{
64 .title = F.message(),
65 .kind = std::string(CodeAction::QUICKFIX_KIND),
66 .edit = std::move(WE),
67 });
68 }
69 }
70
71 // Add refactoring code actions based on cursor position
72 if (TU->ast() && TU->parentMap()) {
73 nixf::PositionRange NixfRange = toNixfRange(Range);
74 if (const nixf::Node *N = TU->ast()->descend(NixfRange)) {
75 addAttrNameActions(*N, *TU->parentMap(), FileURI, TU->src(), Actions);
76 addConvertToInheritAction(*N, *TU->parentMap(), FileURI, TU->src(),
77 Actions);
78 addFlattenAttrsAction(*N, *TU->parentMap(), FileURI, TU->src(),
79 Actions);
80 addPackAttrsAction(*N, *TU->parentMap(), FileURI, TU->src(), Actions);
81 addInheritToBindingAction(*N, *TU->parentMap(), FileURI, TU->src(),
82 Actions);
83 addNoogleDocAction(*N, *TU->parentMap(), Actions);
84 addRewriteStringAction(*N, *TU->parentMap(), FileURI, TU->src(),
85 Actions);
86
87 // Extract to file requires variable lookup analysis
88 if (TU->variableLookup()) {
89 addExtractToFileAction(*N, *TU->parentMap(), *TU->variableLookup(),
90 FileURI, TU->src(), Actions);
91 }
92 // Add with-to-let action (requires VLA for variable tracking)
93 if (TU->variableLookup()) {
94 addWithToLetAction(*N, *TU->parentMap(), *TU->variableLookup(),
95 FileURI, TU->src(), Actions);
96 }
97 }
98 }
99
100 // Selection-based actions (work on arbitrary text, not AST nodes)
101 addJsonToNixAction(TU->src(), Range, FileURI, Actions);
102
103 return Actions;
104 }());
105 };
106 boost::asio::post(Pool, std::move(Action));
107}
108
109void Controller::onCodeActionResolve(const lspserver::CodeAction &Params,
110 Callback<CodeAction> Reply) {
111 auto Action = [Reply = std::move(Reply), Params, this]() mutable {
112 // Check if this is a Noogle documentation action
113 if (Params.data) {
114 const auto *DataObj = Params.data->getAsObject();
115 if (DataObj) {
116 auto NoogleUrl = DataObj->getString("noogleUrl");
117 if (NoogleUrl) {
118 // Call window/showDocument to open the URL in external browser
119 ShowDocumentParams ShowParams;
120 ShowParams.externalUri = NoogleUrl->str();
121 ShowParams.external = true;
122
123 ShowDocument(
124 ShowParams, [](llvm::Expected<ShowDocumentResult> Result) {
125 if (!Result) {
126 lspserver::elog("Failed to open Noogle documentation: {0}",
127 Result.takeError());
128 }
129 });
130 }
131 }
132 }
133
134 // Return the resolved code action (unchanged for Noogle actions since
135 // the work is done via showDocument)
136 Reply(Params);
137 };
138 boost::asio::post(Pool, std::move(Action));
139}
140
141} // namespace nixd
Code action for quoting/unquoting attribute names.
#define CheckDefault(x)
Variant of CheckReturn, but returns default constructed CheckTy.
Definition CheckReturn.h:16
Code action for converting bindings to inherit syntax.
Convert between LSP and nixf types.
Code action for extracting expressions to separate files.
Code action for flattening nested attribute sets.
Code action for converting inherit to explicit binding.
Code action for converting JSON to Nix expressions.
Code action for opening noogle.dev documentation.
Code action for packing dotted attribute paths into nested sets.
Code action for converting between string literal syntaxes.
Code action for converting with expressions to let/inherit.
llvm::unique_function< void(llvm::Expected< T >)> Callback
Definition Function.h:14
void elog(const char *Fmt, Ts &&...Vals)
Definition Logger.h:52
void addJsonToNixAction(llvm::StringRef Src, const lspserver::Range &Range, const std::string &FileURI, std::vector< lspserver::CodeAction > &Actions)
Add JSON to Nix conversion action for selected JSON text.
Definition JsonToNix.cpp:97
void addRewriteStringAction(const nixf::Node &N, const nixf::ParentMapAnalysis &PM, const std::string &FileURI, llvm::StringRef Src, std::vector< lspserver::CodeAction > &Actions)
Add rewrite action for string literal syntax conversion.
nixf::PositionRange toNixfRange(const lspserver::Range &P)
Definition Convert.cpp:36
void addPackAttrsAction(const nixf::Node &N, const nixf::ParentMapAnalysis &PM, const std::string &FileURI, llvm::StringRef Src, std::vector< lspserver::CodeAction > &Actions)
Add pack action for dotted attribute paths.
void addConvertToInheritAction(const nixf::Node &N, const nixf::ParentMapAnalysis &PM, const std::string &FileURI, llvm::StringRef Src, std::vector< lspserver::CodeAction > &Actions)
Add code action to convert binding to inherit syntax.
void addWithToLetAction(const nixf::Node &N, const nixf::ParentMapAnalysis &PM, const nixf::VariableLookupAnalysis &VLA, const std::string &FileURI, llvm::StringRef Src, std::vector< lspserver::CodeAction > &Actions)
Add code action to convert with expression to let/inherit.
void addFlattenAttrsAction(const nixf::Node &N, const nixf::ParentMapAnalysis &PM, const std::string &FileURI, llvm::StringRef Src, std::vector< lspserver::CodeAction > &Actions)
Add flatten action for nested attribute sets.
void addInheritToBindingAction(const nixf::Node &N, const nixf::ParentMapAnalysis &PM, const std::string &FileURI, llvm::StringRef Src, std::vector< lspserver::CodeAction > &Actions)
Add code action to convert inherit to explicit binding.
void addExtractToFileAction(const nixf::Node &N, const nixf::ParentMapAnalysis &PM, const nixf::VariableLookupAnalysis &VLA, const std::string &FileURI, llvm::StringRef Src, std::vector< lspserver::CodeAction > &Actions)
Add extract-to-file action for selected expressions.
void addAttrNameActions(const nixf::Node &N, const nixf::ParentMapAnalysis &PM, const std::string &FileURI, llvm::StringRef Src, std::vector< lspserver::CodeAction > &Actions)
Add refactoring code actions for attribute names (quote/unquote).
Definition AttrName.cpp:13
lspserver::Range toLSPRange(llvm::StringRef Code, const nixf::LexerCursorRange &R)
Definition Convert.cpp:40
void addNoogleDocAction(const nixf::Node &N, const nixf::ParentMapAnalysis &PM, std::vector< lspserver::CodeAction > &Actions)
Add a code action to open noogle.dev documentation for lib.* functions.
Definition NoogleDoc.cpp:30
Range range
The range for which the command was invoked.
TextDocumentIdentifier textDocument
The document in which the command was invoked.
std::optional< llvm::json::Value > data
static const llvm::StringLiteral QUICKFIX_KIND
bool overlap(const Range &RHS) const
static URIForFile canonicalize(llvm::StringRef AbsPath, llvm::StringRef TUPath)
llvm::StringRef file() const
Retrieves absolute path to the file.