Browse Source

Improved installer for rust-analyzer

pipelines/353213535
eidheim 4 years ago
parent
commit
e9b5548b57
  1. 11
      docs/language_servers.md
  2. 16
      src/filesystem.cpp
  3. 2
      src/filesystem.hpp
  4. 54
      src/notebook.cpp
  5. 2
      src/source_language_protocol.cpp
  6. 4
      src/window.cpp

11
docs/language_servers.md

@ -78,17 +78,12 @@ ln -s `which pyls` /usr/local/bin/python-language-server
- Prerequisites:
- [Rust](https://www.rust-lang.org/tools/install)
Install language server, and create symbolic link to enable server in juCi++:
Install language server:
```sh
rustup component add rust-src
git clone https://github.com/rust-analyzer/rust-analyzer
cd rust-analyzer
cargo xtask install --server
# Usually as root:
ln -s ~/.cargo/bin/rust-analyzer /usr/local/bin/rust-language-server
rustup toolchain install nightly
rustup component add --toolchain nightly rust-src rust-analyzer-preview
```
- Additional setup within a Rust project:

16
src/filesystem.cpp

@ -129,9 +129,12 @@ boost::filesystem::path filesystem::get_home_path() noexcept {
boost::filesystem::path filesystem::get_rust_sysroot_path() noexcept {
auto rust_sysroot_path = [] {
std::string path;
TinyProcessLib::Process process("rustc --print sysroot", "", [&path](const char *buffer, size_t length) {
TinyProcessLib::Process process(
"rustc --print sysroot", "",
[&path](const char *buffer, size_t length) {
path += std::string(buffer, length);
});
},
[](const char *buffer, size_t n) {});
if(process.get_exit_status() == 0) {
while(!path.empty() && (path.back() == '\n' || path.back() == '\r'))
path.pop_back();
@ -144,6 +147,15 @@ boost::filesystem::path filesystem::get_rust_sysroot_path() noexcept {
return path;
}
boost::filesystem::path filesystem::get_rust_nightly_sysroot_path() noexcept {
auto path = get_rust_sysroot_path();
if(path.empty())
return {};
auto filename = path.filename().string();
auto pos = filename.find('-');
return path.parent_path() / (pos != std::string::npos ? "nightly" + filename.substr(pos) : "nightly");
}
boost::filesystem::path filesystem::get_short_path(const boost::filesystem::path &path) noexcept {
#ifdef _WIN32
return path;

2
src/filesystem.hpp

@ -22,6 +22,8 @@ public:
static boost::filesystem::path get_home_path() noexcept;
/// Returns empty path on failure
static boost::filesystem::path get_rust_sysroot_path() noexcept;
/// Returns empty path on failure
static boost::filesystem::path get_rust_nightly_sysroot_path() noexcept;
/// Replaces home path with ~
static boost::filesystem::path get_short_path(const boost::filesystem::path &path) noexcept;
/// Replaces ~ with home path (boost::filesystem does not recognize ~)

54
src/notebook.cpp

@ -173,7 +173,7 @@ bool Notebook::open(const boost::filesystem::path &file_path_, Position position
if(language_id == "chdr" || language_id == "cpphdr" || language_id == "c" || language_id == "cpp" || language_id == "objc")
source_views.emplace_back(new Source::ClangView(file_path, language));
else if(language && !language_protocol_language_id.empty() && !filesystem::find_executable(language_protocol_language_id + "-language-server").empty())
source_views.emplace_back(new Source::LanguageProtocolView(file_path, language, language_protocol_language_id, language_protocol_language_id + "-language-server"));
source_views.emplace_back(new Source::LanguageProtocolView(file_path, language, language_protocol_language_id, filesystem::escape_argument(language_protocol_language_id + "-language-server")));
else if(language && language_protocol_language_id == "rust") {
if(!filesystem::find_executable("rust-analyzer").empty())
source_views.emplace_back(new Source::LanguageProtocolView(file_path, language, language_protocol_language_id, "rust-analyzer"));
@ -183,23 +183,23 @@ bool Notebook::open(const boost::filesystem::path &file_path_, Position position
auto rust_analyzer = sysroot / "bin" / "rust-analyzer";
boost::system::error_code ec;
if(boost::filesystem::exists(rust_analyzer, ec))
source_views.emplace_back(new Source::LanguageProtocolView(file_path, language, language_protocol_language_id, rust_analyzer.string()));
source_views.emplace_back(new Source::LanguageProtocolView(file_path, language, language_protocol_language_id, filesystem::escape_argument(rust_analyzer.string())));
else {
static bool first = true;
std::stringstream stdin_stream, stdout_stream;
if(first && !filesystem::find_executable("rustup").empty()) {
first = false;
if(Terminal::get().process(stdin_stream, stdout_stream, "rustup component list") == 0) {
std::string line;
while(std::getline(stdout_stream, line)) {
if(starts_with(line, "rust-analyzer")) {
auto nightly_sysroot = filesystem::get_rust_nightly_sysroot_path();
if(!nightly_sysroot.empty()) {
auto nightly_rust_analyzer = nightly_sysroot / "bin" / "rust-analyzer";
boost::system::error_code ec;
if(boost::filesystem::exists(nightly_rust_analyzer, ec))
source_views.emplace_back(new Source::LanguageProtocolView(file_path, language, language_protocol_language_id, filesystem::escape_argument(nightly_rust_analyzer.string())));
else {
auto install_rust_analyzer = [this](const std::string &command) {
Gtk::MessageDialog dialog(*static_cast<Gtk::Window *>(get_toplevel()), "Install rust-analyzer (Rust language server)", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO);
dialog.set_default_response(Gtk::RESPONSE_YES);
dialog.set_secondary_text("Would you like to install rust-analyzer through rustup?");
int result = dialog.run();
if(result == Gtk::RESPONSE_YES) {
boost::optional<int> exit_status;
Terminal::get().async_process(std::string("rustup component add rust-src ") + (starts_with(line, "rust-analyzer-preview") ? "rust-analyzer-preview" : "rust-analyzer"), "", [&exit_status](int exit_status_) {
Terminal::get().async_process(std::string(command), "", [&exit_status](int exit_status_) {
exit_status = exit_status_;
});
while(!exit_status) {
@ -209,13 +209,30 @@ bool Notebook::open(const boost::filesystem::path &file_path_, Position position
}
if(exit_status == 0) {
Terminal::get().print("\e[32mSuccessfully\e[m installed rust-analyzer.\n");
if(boost::filesystem::exists(rust_analyzer, ec))
source_views.emplace_back(new Source::LanguageProtocolView(file_path, language, language_protocol_language_id, rust_analyzer.string()));
return true;
}
}
return false;
};
static bool first = true;
if(first && !filesystem::find_executable("rustup").empty()) {
first = false;
std::stringstream stdin_stream, stdout_stream;
if(Terminal::get().process(stdin_stream, stdout_stream, "rustup component list") == 0) {
std::string line;
bool found = false;
while(std::getline(stdout_stream, line)) {
if(starts_with(line, "rust-analyzer")) {
if(install_rust_analyzer(std::string("rustup component add rust-src ") + (starts_with(line, "rust-analyzer-preview") ? "rust-analyzer-preview" : "rust-analyzer")))
source_views.emplace_back(new Source::LanguageProtocolView(file_path, language, language_protocol_language_id, filesystem::escape_argument(rust_analyzer.string())));
found = true;
break;
}
}
if(!found && install_rust_analyzer("rustup component add rust-src && rustup toolchain install nightly && rustup component add --toolchain nightly rust-src rust-analyzer-preview"))
source_views.emplace_back(new Source::LanguageProtocolView(file_path, language, language_protocol_language_id, "rustup run nightly rust-analyzer"));
}
}
}
}
}
@ -238,10 +255,15 @@ bool Notebook::open(const boost::filesystem::path &file_path_, Position position
}
else if(language_id == "rust") {
auto rust_installed = !filesystem::get_rust_sysroot_path().empty();
Terminal::get().print(std::string("\e[33mWarning\e[m: could not find Rust ") + (rust_installed ? "language server" : "installation") + ".\n");
Terminal::get().print("For installation instructions please visit: https://gitlab.com/cppit/jucipp/-/blob/master/docs/language_servers.md#rust.\n");
if(!rust_installed)
if(!rust_installed) {
Terminal::get().print("\e[33mWarning\e[m: could not find Rust. You can install Rust by running the following command in a terminal:\n\n");
Terminal::get().print("curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh\n\n");
Terminal::get().print("You will need to restart juCi++ after installing Rust.\n");
}
else {
Terminal::get().print("\e[33mWarning\e[m: could not find Rust language server.\n");
Terminal::get().print("For installation instructions please visit: https://gitlab.com/cppit/jucipp/-/blob/master/docs/language_servers.md#rust.\n");
}
shown.emplace(language_id);
}
else if(language_id == "go") {

2
src/source_language_protocol.cpp

@ -102,7 +102,7 @@ LanguageProtocol::WorkspaceEdit::WorkspaceEdit(const JSON &workspace_edit, boost
LanguageProtocol::Client::Client(boost::filesystem::path root_path_, std::string language_id_, const std::string &language_server) : root_path(std::move(root_path_)), language_id(std::move(language_id_)) {
process = std::make_unique<TinyProcessLib::Process>(
filesystem::escape_argument(language_server), root_path.string(),
language_server, root_path.string(),
[this](const char *bytes, size_t n) {
server_message_stream.write(bytes, n);
parse_server_message();

4
src/window.cpp

@ -449,8 +449,8 @@ void Window::set_menu_actions() {
menu.add_action("file_new_project_rust", []() {
auto sysroot = filesystem::get_rust_sysroot_path();
if(sysroot.empty()) {
Terminal::get().print("\e[33mWarning\e[m: could not find Rust installation.\n");
Terminal::get().print("For installation instructions please visit: https://gitlab.com/cppit/jucipp/-/blob/master/docs/language_servers.md#rust.\n");
Terminal::get().print("\e[31mError\e[m: could not find Rust. You can install Rust by running the following command in a terminal:\n\n");
Terminal::get().print("curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh\n\n");
Terminal::get().print("You will need to restart juCi++ after installing Rust.\n");
return;
}

Loading…
Cancel
Save