19#include <boost/asio/post.hpp>
45 SM_Deprecated = 1 << 1,
49struct RawSemanticToken {
50 lspserver::Position Pos;
51 bool operator<(
const RawSemanticToken &Other)
const {
52 return Pos < Other.Pos;
56 unsigned TokenModifiers;
59class SemanticTokenBuilder {
61 const VariableLookupAnalysis &VLA;
63 nixf::Position Previous = {0, 0};
65 std::vector<RawSemanticToken> Raw;
70 SemanticTokenBuilder(
const VariableLookupAnalysis &VLA, llvm::StringRef Src)
71 : VLA(VLA), Src(Src) {}
72 void addImpl(nixf::LexerCursor Pos,
unsigned Length,
unsigned TokenType,
73 unsigned TokenModifiers) {
75 Raw.emplace_back(RawSemanticToken{P, Length, TokenType, TokenModifiers});
78 void add(
const Node &N,
unsigned TokenType,
unsigned TokenModifiers) {
81 addImpl(N.
lCur(), len(N), TokenType, TokenModifiers);
84 static bool skip(
const Node &N) {
89 static unsigned len(
const Node &N) {
93 void dfs(
const ExprString &Str) {
94 unsigned Modifers = 0;
97 add(Str, ST_String, Modifers);
100 void dfs(
const ExprVar &Var) {
101 if (Var.
id().
name() ==
"true" || Var.
id().
name() ==
"false") {
102 add(Var, ST_Bool, SM_Builtin);
106 if (Var.
id().
name() ==
"null") {
107 add(Var, ST_Null, 0);
111 auto Result = VLA.query(Var);
113 if (Result.Def && Result.Def->isBuiltin()) {
114 add(Var, ST_Builtin, SM_Builtin);
117 if (Result.Kind == ResultKind::Defined) {
118 add(Var, ST_Defined, 0);
121 if (Result.Kind == ResultKind::FromWith) {
122 add(Var, ST_FromWith, SM_Dynamic);
126 add(Var, ST_Defined, SM_Deprecated);
129 void dfs(
const ExprSelect &Select) {
134 for (
const std::shared_ptr<nixf::AttrName> &Name : Select.
path()->
names()) {
137 const AttrName &AN = *Name;
140 add(AN, ST_Select, 0);
146 void dfs(
const SemaAttrs &SA) {
147 for (
const auto &[Name, Attr] : SA.
staticAttrs()) {
153 if (Attr.fromInherit())
155 add(Attr.key(), ST_AttrName, 0);
163 void dfs(
const LambdaArg &Arg) {
165 add(*Arg.
id(), ST_LambdaArg, 0);
168 for (
const auto &[_, Formal] : Arg.
formals()->
dedup()) {
170 add(*Formal->id(), ST_LambdaFormal, 0);
175 void dfs(
const ExprLambda &Lambda) {
182 void dfs(
const Node *AST) {
185 switch (AST->
kind()) {
186 case Node::NK_ExprLambda: {
187 const auto &Lambda =
static_cast<const ExprLambda &
>(*AST);
191 case Node::NK_ExprString: {
192 const auto &Str =
static_cast<const ExprString &
>(*AST);
196 case Node::NK_ExprVar: {
197 const auto &Var =
static_cast<const ExprVar &
>(*AST);
201 case Node::NK_ExprSelect: {
202 const auto &Select =
static_cast<const ExprSelect &
>(*AST);
206 case Node::NK_ExprAttrs: {
207 const SemaAttrs &SA =
static_cast<const ExprAttrs &
>(*AST).sema();
212 for (
const Node *Ch : AST->
children()) {
218 std::vector<SemanticToken> finish() {
219 std::vector<SemanticToken> Tokens;
220 std::sort(Raw.begin(), Raw.end());
221 lspserver::Position Prev{0, 0};
222 for (
auto Elm : Raw) {
223 assert(Elm.Pos.line - Prev.line >= 0);
224 unsigned DeltaLine = Elm.Pos.line - Prev.line;
226 DeltaLine ? Elm.Pos.character : Elm.Pos.character - Prev.character;
228 Tokens.emplace_back(DeltaLine, DeltaCol, Elm.Length, Elm.TokenType,
239 using CheckTy = SemanticTokens;
240 auto Action = [Reply = std::move(Reply), URI = Params.
textDocument.
uri,
242 const auto File = URI.file();
243 return Reply([&]() -> llvm::Expected<CheckTy> {
246 SemanticTokenBuilder Builder(*TU->variableLookup(), TU->src());
247 Builder.dfs(AST.get());
248 return SemanticTokens{.tokens = Builder.finish()};
251 boost::asio::post(Pool, std::move(Action));
#define CheckDefault(x)
Variant of CheckReturn, but returns default constructed CheckTy
Convert between LSP and nixf types.
VariableLookupAnalysis::LookupResultKind ResultKind
Lookup variable names, from it's parent scope.
AttrNameKind kind() const
const std::vector< std::shared_ptr< AttrName > > & names() const
Expr * defaultExpr() const
const Identifier & id() const
const std::string & name() const
Formals * formals() const
std::size_t offset() const
Offset in the source file, starting from 0.
int64_t line() const
Line number, starting from 0.
LexerCursorRange range() const
virtual ChildVector children() const =0
const std::vector< Attribute > & dynamicAttrs() const
Dynamic attributes, require evaluation to get the key.
const std::map< std::string, Attribute > & staticAttrs() const
Static attributes, do not require evaluation to get the key.
Whether current platform treats paths case insensitively.
llvm::unique_function< void(llvm::Expected< T >)> Callback
bool operator<(const CompletionItem &, const CompletionItem &)
lspserver::Position toLSPPosition(llvm::StringRef Code, const nixf::LexerCursor &P)
Body of textDocument/semanticTokens/full request.
TextDocumentIdentifier textDocument
The text document.
URIForFile uri
The text document's URI.