Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ class AttrSetClient : public lspserver::LSPServer {

void exit() { Exit(nullptr); }

void setLoggingEnabled(bool Enabled) {
LSPServer::setLoggingEnabled(Enabled);
}

/// Get executable path for launching the server.
/// \returns null terminated string.
static const char *getExe();
Expand Down
15 changes: 15 additions & 0 deletions common/include/nixd/Eval/Spawn.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#pragma once

#include "nixd/Eval/AttrSetClient.h"

#include <memory>
#include <string_view>

namespace nixd {

/// Launches an attrset evaluator process whose stderr is redirected to
/// `WorkerStderr`.
void spawnAttrSetEval(std::string_view WorkerStderr,
std::unique_ptr<AttrSetClientProc> &Worker);

} // namespace nixd
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ struct AttrPathCompleteParams {
Selector Scope;
/// \brief Search for packages prefixed with this "prefix"
std::string Prefix;
std::optional<int> MaxItems;
};

llvm::json::Value toJSON(const AttrPathCompleteParams &Params);
Expand Down
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -162,9 +162,9 @@ void fillOptionDescription(nix::EvalState &State, nix::Value &V,

std::vector<std::string> completeNames(nix::Value &Scope,
const nix::EvalState &State,
std::string_view Prefix) {
int Num = 0;
std::string_view Prefix, int Limit) {
std::vector<std::string> Names;
const bool Unlimited = Limit <= 0;

// FIXME: we may want to use "Trie" to speedup the string searching.
// However as my (roughtly) profiling the critical in this loop is
Expand All @@ -174,10 +174,9 @@ std::vector<std::string> completeNames(nix::Value &Scope,
const nix::Attr &Attr = *AttrPtr;
const std::string_view Name = State.symbols[Attr.name];
if (Name.starts_with(Prefix)) {
++Num;
Names.emplace_back(Name);
// We set this a very limited number as to speedup
if (Num > MaxItems)
if (!Unlimited && Names.size() >= static_cast<std::size_t>(Limit))
break;
}
}
Expand Down Expand Up @@ -288,7 +287,8 @@ void AttrSetProvider::onAttrPathComplete(
return;
}

return Reply(completeNames(Scope, state(), Params.Prefix));
const int Limit = Params.MaxItems.value_or(MaxItems);
return Reply(completeNames(Scope, state(), Params.Prefix, Limit));
} catch (const nix::BaseError &Err) {
return Reply(error(Err.info().msg.str()));
} catch (const std::exception &Err) {
Expand Down
24 changes: 24 additions & 0 deletions common/lib/Eval/Spawn.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#include "nixd/Eval/Spawn.h"

#include <unistd.h>

#include <cstdio>
#include <string>

namespace nixd {

namespace {
constexpr std::string_view NullDevice{"/dev/null"};
}

void spawnAttrSetEval(std::string_view WorkerStderr,
std::unique_ptr<AttrSetClientProc> &Worker) {
std::string Path = WorkerStderr.empty() ? std::string(NullDevice)
: std::string(WorkerStderr);
Worker = std::make_unique<AttrSetClientProc>([Path = std::move(Path)]() {
freopen(Path.c_str(), "w", stderr);
return execl(AttrSetClient::getExe(), "nixd-attrset-eval", nullptr);
});
}

} // namespace nixd
Original file line number Diff line number Diff line change
Expand Up @@ -112,15 +112,17 @@ bool nixd::fromJSON(const llvm::json::Value &Params, AttrPathInfoResponse &R,
}

Value nixd::toJSON(const AttrPathCompleteParams &Params) {
return Object{{"Scope", Params.Scope}, {"Prefix", Params.Prefix}};
return Object{{"Scope", Params.Scope},
{"Prefix", Params.Prefix},
{"MaxItems", Params.MaxItems}};
}
bool nixd::fromJSON(const llvm::json::Value &Params, AttrPathCompleteParams &R,
llvm::json::Path P) {
ObjectMapper O(Params, P);
return O //
&& O.map("Scope", R.Scope) //
&& O.map("Prefix", R.Prefix) //
;
return O //
&& O.map("Scope", R.Scope) //
&& O.map("Prefix", R.Prefix) //
&& O.mapOptional("MaxItems", R.MaxItems); //
}

llvm::json::Value nixd::toJSON(const ValueDescription &Params) {
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
84 changes: 84 additions & 0 deletions common/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
project('nixd-common', ['cpp'], default_options : ['cpp_std=gnu++20'], version : 'nightly')

config_h = configuration_data()

git = find_program('git', required : false)
if git.found()
res = run_command([git, 'describe', '--tags', '--always'], capture : true, check : false)
describe = res.stdout().strip()
if describe != ''
config_h.set_quoted('NIXD_VCS_TAG', describe)
endif
endif

config_h.set_quoted('NIXD_VERSION', meson.project_version())
config_h.set_quoted('NIXD_LIBEXEC', get_option('prefix') / get_option('libexecdir'))

configure_file(
output : 'nixd-config.h',
configuration : config_h,
)

cpp = meson.get_compiler('cpp')

add_project_arguments([
'-I' + meson.project_build_root(),
cpp.get_supported_arguments(
'-Werror=documentation',
'-Werror=delete-non-abstract-non-virtual-dtor',
'-Werror=pragma-once-outside-header',
'-Wno-unused-parameter',
'-Wno-missing-field-initializers'
),
], language : 'cpp')

if get_option('buildtype').startswith('debug')
add_project_arguments([
cpp.get_supported_arguments('-Werror=return-type'),
], language : 'cpp')
endif

if get_option('buildtype').startswith('release')
add_project_arguments([
cpp.get_supported_arguments(
'-Wno-return-type',
'-Wno-maybe-uninitialized',
'-Wno-unused-variable'
),
], language : 'cpp')
endif

llvm = dependency('llvm')
nixd_lsp_server = dependency('nixd-lspserver', fallback : ['nixd-lspserver', 'nixd_lsp_server'])
nixt = dependency('nixt', fallback : ['libnixt', 'nixt'])

common_inc = include_directories('include')

common_deps = [nixd_lsp_server, llvm, nixt]

nixd_common_lib = library(
'nixd-common',
'lib/Eval/AttrSetClient.cpp',
'lib/Eval/AttrSetProvider.cpp',
'lib/Eval/Spawn.cpp',
'lib/Protocol/AttrSet.cpp',
'lib/CommandLine/Options.cpp',
'lib/Support/AutoCloseFD.cpp',
'lib/Support/ForkPiped.cpp',
'lib/Support/StreamProc.cpp',
include_directories : common_inc,
dependencies : common_deps,
install : true,
)

subdir('tools')

nixd_common = declare_dependency(
include_directories : common_inc,
link_with : nixd_common_lib,
dependencies : common_deps,
)

meson.override_dependency('nixd-common', nixd_common)

install_subdir('include', install_dir : 'include')
1 change: 1 addition & 0 deletions common/subprojects/libnixt
1 change: 1 addition & 0 deletions common/subprojects/nixd-lspserver
11 changes: 11 additions & 0 deletions common/tools/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
nixd_attrset_eval = executable(
'nixd-attrset-eval',
'nixd-attrset-eval.cpp',
include_directories : common_inc,
link_with : nixd_common_lib,
dependencies : common_deps,
install : true,
install_dir : get_option('libexecdir'),
)

meson.override_find_program('nixd-attrset-eval', nixd_attrset_eval)
File renamed without changes.
4 changes: 3 additions & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@
;
nixComponents = nixVersions.nixComponents_2_30;
llvmPackages = llvmPackages_19;
nixf = callPackage ./libnixf { };
nixf = callPackage ./libnixf {
inherit llvmPackages nixComponents;
};
nixt = callPackage ./libnixt { inherit nixComponents; };
nixd = callPackage ./nixd {
inherit nixComponents nixf nixt;
Expand Down
8 changes: 7 additions & 1 deletion libnixf/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
boost,
nlohmann_json,
python312,
llvmPackages,
nixComponents,
}:

stdenv.mkDerivation {
Expand Down Expand Up @@ -39,8 +41,12 @@ stdenv.mkDerivation {
nativeCheckInputs = [ lit ];

buildInputs = [
gtest
boost
gtest
llvmPackages.llvm
nixComponents.nix-cmd
nixComponents.nix-expr
nixComponents.nix-main
nlohmann_json
];

Expand Down
24 changes: 24 additions & 0 deletions libnixf/include/nixf/Basic/Nodes/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,30 @@ class ExprWith : public Expr {
[[nodiscard]] ChildVector children() const override {
return {KwWith.get(), TokSemi.get(), With.get(), E.get()};
}

[[nodiscard]] std::vector<std::string> selector() const {
std::vector<std::string> Parts;
for (const auto &Child : With->children()) {
if (!Child)
continue;
switch (Child->kind()) {
case Node::NK_ExprVar: {
const auto &Var = static_cast<const ExprVar &>(*Child);
Parts.emplace_back(Var.id().name());
break;
}
case Node::NK_AttrPath: {
const auto &Path = static_cast<const AttrPath &>(*Child);
for (const auto &Name : Path.names())
Parts.emplace_back(Name->id()->name());
break;
}
default:
break;
}
}
return Parts;
}
};

} // namespace nixf
19 changes: 19 additions & 0 deletions libnixf/include/nixf/Sema/VariableLookup.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,15 @@
#include <map>
#include <memory>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>

namespace nixd {
class AttrSetClient;
class AttrSetClientProc;
} // namespace nixd

namespace nixf {

/// \brief Represents a definition
Expand Down Expand Up @@ -162,8 +169,16 @@ class VariableLookupAnalysis {

std::map<const ExprVar *, LookupResult> Results;

std::unique_ptr<nixd::AttrSetClientProc> NixpkgsEval;
nixd::AttrSetClient *NixpkgsClient = nullptr;
std::unordered_map<std::string, std::unordered_set<std::string>>
NixpkgsKnownAttrs;
const std::unordered_set<std::string> *
ensureNixpkgsKnownAttrsCached(const std::vector<std::string> &Scope);

public:
VariableLookupAnalysis(std::vector<Diagnostic> &Diags);
~VariableLookupAnalysis();

/// \brief Perform variable lookup analysis (def-use) on AST.
/// \note This method should be invoked after any other method called.
Expand Down Expand Up @@ -196,6 +211,10 @@ class VariableLookupAnalysis {
}

const EnvNode *env(const Node *N) const;

[[nodiscard]] nixd::AttrSetClient *nixpkgsClient() const {
return NixpkgsClient;
}
};

} // namespace nixf
2 changes: 2 additions & 0 deletions libnixf/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ boost = dependency('boost')
gtest = dependency('gtest')
gtest_main = dependency('gtest_main')

nixd_common = dependency('nixd-common', fallback : ['common', 'nixd_common'])

pkgconfig = import('pkgconfig')


Expand Down
Loading