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: - Prerequisites:
- [Rust](https://www.rust-lang.org/tools/install) - [Rust](https://www.rust-lang.org/tools/install)
Install language server, and create symbolic link to enable server in juCi++: Install language server:
```sh ```sh
rustup component add rust-src rustup component add rust-src
rustup toolchain install nightly
git clone https://github.com/rust-analyzer/rust-analyzer rustup component add --toolchain nightly rust-src rust-analyzer-preview
cd rust-analyzer
cargo xtask install --server
# Usually as root:
ln -s ~/.cargo/bin/rust-analyzer /usr/local/bin/rust-language-server
``` ```
- Additional setup within a Rust project: - 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 { boost::filesystem::path filesystem::get_rust_sysroot_path() noexcept {
auto rust_sysroot_path = [] { auto rust_sysroot_path = [] {
std::string 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); path += std::string(buffer, length);
}); },
[](const char *buffer, size_t n) {});
if(process.get_exit_status() == 0) { if(process.get_exit_status() == 0) {
while(!path.empty() && (path.back() == '\n' || path.back() == '\r')) while(!path.empty() && (path.back() == '\n' || path.back() == '\r'))
path.pop_back(); path.pop_back();
@ -144,6 +147,15 @@ boost::filesystem::path filesystem::get_rust_sysroot_path() noexcept {
return path; 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 { boost::filesystem::path filesystem::get_short_path(const boost::filesystem::path &path) noexcept {
#ifdef _WIN32 #ifdef _WIN32
return path; return path;

2
src/filesystem.hpp

@ -22,6 +22,8 @@ public:
static boost::filesystem::path get_home_path() noexcept; static boost::filesystem::path get_home_path() noexcept;
/// Returns empty path on failure /// Returns empty path on failure
static boost::filesystem::path get_rust_sysroot_path() noexcept; 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 ~ /// Replaces home path with ~
static boost::filesystem::path get_short_path(const boost::filesystem::path &path) noexcept; static boost::filesystem::path get_short_path(const boost::filesystem::path &path) noexcept;
/// Replaces ~ with home path (boost::filesystem does not recognize ~) /// 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") 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)); 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()) 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") { else if(language && language_protocol_language_id == "rust") {
if(!filesystem::find_executable("rust-analyzer").empty()) if(!filesystem::find_executable("rust-analyzer").empty())
source_views.emplace_back(new Source::LanguageProtocolView(file_path, language, language_protocol_language_id, "rust-analyzer")); 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"; auto rust_analyzer = sysroot / "bin" / "rust-analyzer";
boost::system::error_code ec; boost::system::error_code ec;
if(boost::filesystem::exists(rust_analyzer, 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 { else {
static bool first = true; auto nightly_sysroot = filesystem::get_rust_nightly_sysroot_path();
std::stringstream stdin_stream, stdout_stream; if(!nightly_sysroot.empty()) {
if(first && !filesystem::find_executable("rustup").empty()) { auto nightly_rust_analyzer = nightly_sysroot / "bin" / "rust-analyzer";
first = false; boost::system::error_code ec;
if(Terminal::get().process(stdin_stream, stdout_stream, "rustup component list") == 0) { if(boost::filesystem::exists(nightly_rust_analyzer, ec))
std::string line; source_views.emplace_back(new Source::LanguageProtocolView(file_path, language, language_protocol_language_id, filesystem::escape_argument(nightly_rust_analyzer.string())));
while(std::getline(stdout_stream, line)) { else {
if(starts_with(line, "rust-analyzer")) { 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); 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_default_response(Gtk::RESPONSE_YES);
dialog.set_secondary_text("Would you like to install rust-analyzer through rustup?"); dialog.set_secondary_text("Would you like to install rust-analyzer through rustup?");
int result = dialog.run(); int result = dialog.run();
if(result == Gtk::RESPONSE_YES) { if(result == Gtk::RESPONSE_YES) {
boost::optional<int> exit_status; 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_; exit_status = exit_status_;
}); });
while(!exit_status) { while(!exit_status) {
@ -209,13 +209,30 @@ bool Notebook::open(const boost::filesystem::path &file_path_, Position position
} }
if(exit_status == 0) { if(exit_status == 0) {
Terminal::get().print("\e[32mSuccessfully\e[m installed rust-analyzer.\n"); Terminal::get().print("\e[32mSuccessfully\e[m installed rust-analyzer.\n");
if(boost::filesystem::exists(rust_analyzer, ec)) return true;
source_views.emplace_back(new Source::LanguageProtocolView(file_path, language, language_protocol_language_id, rust_analyzer.string()));
} }
} }
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; 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") { else if(language_id == "rust") {
auto rust_installed = !filesystem::get_rust_sysroot_path().empty(); 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"); if(!rust_installed) {
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[33mWarning\e[m: could not find Rust. You can install Rust by running the following command in a terminal:\n\n");
if(!rust_installed) 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"); 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); shown.emplace(language_id);
} }
else if(language_id == "go") { 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_)) { 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>( 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) { [this](const char *bytes, size_t n) {
server_message_stream.write(bytes, n); server_message_stream.write(bytes, n);
parse_server_message(); parse_server_message();

4
src/window.cpp

@ -449,8 +449,8 @@ void Window::set_menu_actions() {
menu.add_action("file_new_project_rust", []() { menu.add_action("file_new_project_rust", []() {
auto sysroot = filesystem::get_rust_sysroot_path(); auto sysroot = filesystem::get_rust_sysroot_path();
if(sysroot.empty()) { if(sysroot.empty()) {
Terminal::get().print("\e[33mWarning\e[m: could not find Rust installation.\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("For installation instructions please visit: https://gitlab.com/cppit/jucipp/-/blob/master/docs/language_servers.md#rust.\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"); Terminal::get().print("You will need to restart juCi++ after installing Rust.\n");
return; return;
} }

Loading…
Cancel
Save