nixd
Loading...
Searching...
No Matches
DocumentLink.cpp
Go to the documentation of this file.
1/// \file
2/// \brief Implementation of [Document Link].
3/// [Document Link]:
4/// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_documentLink
5///
6/// In Nix language, there are a few interesting constructs worth highlighting:
7///
8/// 1. URL literal. Writing URls directly without quotes, supported by vscode.
9/// 2. Path. (Append "default.nix", perhaps)
10/// 3. Search Path <>
11/// FIXME: support search path.
12/// 4. Home Path: (begins with ~)
13/// FIXME: support home path.
14/// 5. Flake Reference
15/// FIXME: support flake ref
16///
17
18#include "Convert.h"
19
21
22#include <boost/asio/post.hpp>
23
24#include <filesystem>
25
26using namespace nixd;
27using namespace lspserver;
28using namespace nixf;
29
30namespace {
31
32/// \brief Resolve expr path to "real" path.
33std::optional<std::string> resolveExprPath(const std::string &BasePath,
34 const std::string &ExprPath) {
35
36 namespace fs = std::filesystem;
37 // FIXME: we do not use complete "symbolic resolve" here.
38 fs::path Path = fs::absolute((BasePath)).remove_filename().append(ExprPath);
39
40 if (!fs::exists(Path))
41 return std::nullopt;
42
43 if (fs::is_directory(Path))
44 return Path.append("default.nix");
45
46 return Path;
47}
48
49void dfs(const Node *N, const std::string &BasePath,
50 std::vector<DocumentLink> &Links, llvm::StringRef Src) {
51 if (!N)
52 return;
53
54 switch (N->kind()) {
55 case Node::NK_ExprPath: {
56 // Resolve the path.
57 const auto &Path = static_cast<const ExprPath &>(*N);
58 if (Path.parts().isLiteral()) {
59 // Provide literal path linking.
60 if (auto Link = resolveExprPath(BasePath, Path.parts().literal())) {
61 Links.emplace_back(
62 DocumentLink{.range = toLSPRange(Src, N->range()),
63 .target = URIForFile::canonicalize(*Link, *Link)});
64 }
65 }
66 return;
67 }
68 default:
69 break;
70 }
71
72 // Traverse on all children
73 for (const Node *Ch : N->children()) {
74 dfs(Ch, BasePath, Links, Src);
75 }
76}
77
78} // namespace
79
80void Controller::onDocumentLink(
82 lspserver::Callback<std::vector<DocumentLink>> Reply) {
83 auto Action = [File = Params.textDocument.uri.file().str(),
84 Reply = std::move(Reply), this]() mutable {
85 if (std::shared_ptr<NixTU> TU = getTU(File, Reply)) [[likely]] {
86 if (std::shared_ptr<nixf::Node> AST = getAST(*TU, Reply)) [[likely]] {
87 // Traverse the AST, provide the links
88 std::vector<DocumentLink> Links;
89 dfs(AST.get(), File, Links, TU->src());
90 Reply(std::move(Links));
91 }
92 }
93 };
94 boost::asio::post(Pool, std::move(Action));
95}
Convert between LSP and nixf types.
Whether current platform treats paths case insensitively.
Definition Connection.h:11
llvm::unique_function< void(llvm::Expected< T >)> Callback
Definition Function.h:14
std::string Path
Definition Path.h:24
bool fromJSON(const llvm::json::Value &Params, Configuration::Diagnostic &R, llvm::json::Path P)
lspserver::Range toLSPRange(llvm::StringRef Code, const nixf::LexerCursorRange &R)
Definition Convert.cpp:40
Parameters for the document link request.
static URIForFile canonicalize(llvm::StringRef AbsPath, llvm::StringRef TUPath)