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 "CheckReturn.h"
19#include "Convert.h"
20
22
23#include <boost/asio/post.hpp>
24
25#include <filesystem>
26
27using namespace nixd;
28using namespace lspserver;
29using namespace nixf;
30
31namespace {
32
33/// \brief Resolve expr path to "real" path.
34std::optional<std::string> resolveExprPath(const std::string &BasePath,
35 const std::string &ExprPath) {
36
37 namespace fs = std::filesystem;
38 // FIXME: we do not use complete "symbolic resolve" here.
39 fs::path Path = fs::absolute((BasePath)).remove_filename().append(ExprPath);
40
41 if (!fs::exists(Path))
42 return std::nullopt;
43
44 if (fs::is_directory(Path))
45 return Path.append("default.nix");
46
47 return Path;
48}
49
50void dfs(const Node *N, const std::string &BasePath,
51 std::vector<DocumentLink> &Links, llvm::StringRef Src) {
52 if (!N)
53 return;
54
55 switch (N->kind()) {
56 case Node::NK_ExprPath: {
57 // Resolve the path.
58 const auto &Path = static_cast<const ExprPath &>(*N);
59 if (Path.parts().isLiteral()) {
60 // Provide literal path linking.
61 if (auto Link = resolveExprPath(BasePath, Path.parts().literal())) {
62 Links.emplace_back(
63 DocumentLink{.range = toLSPRange(Src, N->range()),
64 .target = URIForFile::canonicalize(*Link, *Link)});
65 }
66 }
67 return;
68 }
69 default:
70 break;
71 }
72
73 // Traverse on all children
74 for (const Node *Ch : N->children()) {
75 dfs(Ch, BasePath, Links, Src);
76 }
77}
78
79} // namespace
80
81void Controller::onDocumentLink(
82 const DocumentLinkParams &Params,
83 lspserver::Callback<std::vector<DocumentLink>> Reply) {
84 using CheckTy = std::vector<DocumentLink>;
85 auto Action = [File = Params.textDocument.uri.file().str(),
86 Reply = std::move(Reply), this]() mutable {
87 return Reply([&]() -> llvm::Expected<CheckTy> {
88 const auto TU = CheckDefault(getTU(File));
89 const auto AST = CheckDefault(getAST(*TU));
90
91 // Traverse the AST, provide the links
92 std::vector<DocumentLink> Links;
93 dfs(AST.get(), File, Links, TU->src());
94 return Links;
95 }());
96 };
97 boost::asio::post(Pool, std::move(Action));
98}
#define CheckDefault(x)
Variant of CheckReturn, but returns default constructed CheckTy
Definition CheckReturn.h:16
Convert between LSP and nixf types.
NodeKind kind() const
Definition Basic.h:34
LexerCursorRange range() const
Definition Basic.h:35
virtual ChildVector children() const =0
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
lspserver::Range toLSPRange(llvm::StringRef Code, const nixf::LexerCursorRange &R)
Definition Convert.cpp:40
Parameters for the document link request.
TextDocumentIdentifier textDocument
The document to provide document links for.
static URIForFile canonicalize(llvm::StringRef AbsPath, llvm::StringRef TUPath)
llvm::StringRef file() const
Retrieves absolute path to the file.