nixd
Loading...
Searching...
No Matches
Rename.cpp
Go to the documentation of this file.
1/// \file
2/// \brief This implements [Rename].
3/// [Rename]:
4/// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_rename
5
6#include "Convert.h"
7#include "Definition.h"
8
11
12#include <boost/asio/post.hpp>
13
14#include <exception>
15
16using namespace lspserver;
17using namespace nixd;
18using namespace llvm;
19using namespace nixf;
20
21namespace {
22
23struct RenameException : std::exception {};
24
25struct RenameWithException : RenameException {
26 [[nodiscard]] const char *what() const noexcept override {
27 return "cannot rename `with` defined variable";
28 }
29};
30
31struct RenameBuiltinException : RenameException {
32 [[nodiscard]] const char *what() const noexcept override {
33 return "cannot rename builtin variable";
34 }
35};
36
37WorkspaceEdit rename(const nixf::Node &Desc, const std::string &NewText,
38 const ParentMapAnalysis &PMA,
39 const VariableLookupAnalysis &VLA, const URIForFile &URI,
40 llvm::StringRef Src) {
42 // Find "definition"
43 auto Def = findDefinition(Desc, PMA, VLA);
44
45 if (Def.source() == Definition::DS_With)
46 throw RenameWithException();
47
48 if (Def.isBuiltin())
49 throw RenameBuiltinException();
50
51 std::vector<TextEdit> Edits;
52
53 for (const auto *Use : Def.uses()) {
54 Edits.emplace_back(TextEdit{
55 .range = toLSPRange(Src, Use->range()),
56 .newText = NewText,
57 });
58 }
59
60 Edits.emplace_back(TextEdit{
61 .range = toLSPRange(Src, Def.syntax()->range()),
62 .newText = NewText,
63 });
65 WE.changes = std::map<std::string, std::vector<TextEdit>>{
66 {URI.uri(), std::move(Edits)}};
67 return WE;
68}
69} // namespace
70
71void Controller::onRename(const RenameParams &Params,
73 auto Action = [Reply = std::move(Reply), URI = Params.textDocument.uri,
74 Pos = toNixfPosition(Params.position),
75 NewText = Params.newName, this]() mutable {
76 std::string File(URI.file());
77 if (std::shared_ptr<NixTU> TU = getTU(File, Reply)) [[likely]] {
78 if (std::shared_ptr<nixf::Node> AST = getAST(*TU, Reply)) [[likely]] {
79 const nixf::Node *Desc = AST->descend({Pos, Pos});
80 if (!Desc) {
81 Reply(error("cannot find corresponding node on given position"));
82 return;
83 }
84 const auto &PM = *TU->parentMap();
85 const auto &VLA = *TU->variableLookup();
86 try {
87 return Reply(rename(*Desc, NewText, PM, VLA, URI, TU->src()));
88 } catch (std::exception &E) {
89 return Reply(error(E.what()));
90 }
91 }
92 }
93 };
94 boost::asio::post(Pool, std::move(Action));
95}
96
97void Controller::onPrepareRename(
100 auto Action = [Reply = std::move(Reply), URI = Params.textDocument.uri,
101 Pos = toNixfPosition(Params.position), this]() mutable {
102 std::string File(URI.file());
103 if (std::shared_ptr<NixTU> TU = getTU(File, Reply)) [[likely]] {
104 if (std::shared_ptr<nixf::Node> AST = getAST(*TU, Reply)) [[likely]] {
105 const nixf::Node *Desc = AST->descend({Pos, Pos});
106 if (!Desc) {
107 return Reply(
108 error("cannot find corresponding node on given position"));
109 }
110 const auto &PM = *TU->parentMap();
111 const auto &VLA = *TU->variableLookup();
112 try {
113 WorkspaceEdit WE = rename(*Desc, "", PM, VLA, URI, TU->src());
114 return Reply(toLSPRange(TU->src(), Desc->range()));
115 } catch (std::exception &E) {
116 return Reply(error(E.what()));
117 }
118 }
119 }
120 };
121 boost::asio::post(Pool, std::move(Action));
122}
Convert between LSP and nixf types.
@ DS_With
From with <expr>;.
const Node * descend(PositionRange Range) const
Descendant node that contains the given range.
Definition Basic.h:49
Whether current platform treats paths case insensitively.
Definition Connection.h:11
llvm::unique_function< void(llvm::Expected< T >)> Callback
Definition Function.h:14
llvm::Error error(std::error_code EC, const char *Fmt, Ts &&...Vals)
Definition Logger.h:70
bool fromJSON(const llvm::json::Value &Params, Configuration::Diagnostic &R, llvm::json::Path P)
nixf::Position toNixfPosition(const lspserver::Position &P)
Definition Convert.cpp:32
const nixf::Definition & findDefinition(const nixf::Node &N, const nixf::ParentMapAnalysis &PMA, const nixf::VariableLookupAnalysis &VLA)
Heuristically find definition on some node.
lspserver::Range toLSPRange(llvm::StringRef Code, const nixf::LexerCursorRange &R)
Definition Convert.cpp:40
std::optional< std::map< std::string, std::vector< TextEdit > > > changes
Holds changes to existing resources.