From 68fe6bab1a64cf69f1ad6244f19c026a2621fdae Mon Sep 17 00:00:00 2001 From: eidheim Date: Mon, 7 Jun 2021 11:59:13 +0200 Subject: [PATCH] Added compile and run support for Julia --- docs/language_servers.md | 29 ++++++++++++++++++++ src/project.cpp | 46 +++++++++++++++++++------------- src/project.hpp | 9 +++++++ src/source.cpp | 3 ++- src/source_base.cpp | 5 ++-- src/source_language_protocol.cpp | 2 +- src/tooltips.cpp | 10 ++++--- 7 files changed, 77 insertions(+), 27 deletions(-) diff --git a/docs/language_servers.md b/docs/language_servers.md index 8f02af0..8af301b 100644 --- a/docs/language_servers.md +++ b/docs/language_servers.md @@ -4,6 +4,7 @@ - [Python3](#python3) - [Rust](#rust) - [Go](#go) +- [Julia](#julia) - [GLSL](#glsl) ## JavaScript/TypeScript @@ -110,6 +111,34 @@ ln -s `which gopls` /usr/local/bin/go-language-server - Additional setup within a Go project: - Add an empty `.go-format` file to enable style format on save +## Julia + +- Prerequisites: + - [Julia](https://julialang.org/downloads/) + +Install language server, and create symbolic link to enable server in juCi++: + +```sh +julia -e 'using Pkg;Pkg.add("LanguageServer");Pkg.add("SymbolServer");Pkg.add("StaticLint");' + +# Usually as root: +echo '#!/bin/sh +julia --startup-file=no --history-file=no -e '\'' +using LanguageServer; +using Pkg; +import StaticLint; +import SymbolServer; +env_path = dirname(Pkg.Types.Context().env.project_file); +server = LanguageServer.LanguageServerInstance(stdin, stdout, env_path, ""); +server.runlinter = true; +run(server); +'\''' > /usr/local/bin/julia-language-server +chmod 755 /usr/local/bin/julia-language-server +``` + +- Additional setup within a Julia project: + - Add an empty `.julia-format` file to enable style format on save + ## GLSL Install language server, and create a script to enable server in juCi++: diff --git a/src/project.cpp b/src/project.cpp index 48dfd08..206f206 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -184,6 +184,8 @@ std::shared_ptr Project::create() { return std::shared_ptr(new Project::HTML(std::move(build))); if(language_id == "go") return std::shared_ptr(new Project::Go(std::move(build))); + if(language_id == "julia") + return std::shared_ptr(new Project::Julia(std::move(build))); } } else @@ -853,15 +855,12 @@ void Project::Python::compile_and_run() { command += filesystem::get_short_path(build->project_path).string(); path = build->project_path; } - else { - auto view = Notebook::get().get_current_view(); - if(!view) { - Info::get().print("No executable found"); - return; - } + else if(auto view = Notebook::get().get_current_view()) { command += filesystem::escape_argument(filesystem::get_short_path(view->file_path).string()); path = view->file_path.parent_path(); } + else + return; if(Config::get().terminal.clear_on_compile) Terminal::get().clear(); @@ -879,15 +878,12 @@ void Project::JavaScript::compile_and_run() { command = "npm start"; path = build->project_path; } - else { - auto view = Notebook::get().get_current_view(); - if(!view) { - Info::get().print("No executable found"); - return; - } + else if(auto view = Notebook::get().get_current_view()) { command = "node " + filesystem::escape_argument(filesystem::get_short_path(view->file_path).string()); path = view->file_path.parent_path(); } + else + return; if(Config::get().terminal.clear_on_compile) Terminal::get().clear(); @@ -967,21 +963,33 @@ void Project::Go::compile_and_run() { command = "go run ."; path = build->project_path; } - else { - auto view = Notebook::get().get_current_view(); - if(!view) { - Info::get().print("No executable found"); - return; - } + else if(auto view = Notebook::get().get_current_view()) { command = "go run " + filesystem::escape_argument(filesystem::get_short_path(view->file_path).string()); path = view->file_path.parent_path(); } + else + return; if(Config::get().terminal.clear_on_compile) Terminal::get().clear(); Terminal::get().print("\e[2mRunning: " + command + "\e[m\n"); - Terminal::get().async_process(command, build->project_path, [command](int exit_status) { + Terminal::get().async_process(command, path, [command](int exit_status) { Terminal::get().print("\e[2m" + command + " returned: " + (exit_status == 0 ? "\e[32m" : "\e[31m") + std::to_string(exit_status) + "\e[m\n"); }); } + +void Project::Julia::compile_and_run() { + if(auto view = Notebook::get().get_current_view()) { + auto command = "julia " + filesystem::escape_argument(filesystem::get_short_path(Notebook::get().get_current_view()->file_path).string()); + auto path = view->file_path.parent_path(); + + if(Config::get().terminal.clear_on_compile) + Terminal::get().clear(); + + Terminal::get().print("\e[2mRunning: " + command + "\e[m\n"); + Terminal::get().async_process(command, path, [command](int exit_status) { + Terminal::get().print("\e[2m" + command + " returned: " + (exit_status == 0 ? "\e[32m" : "\e[31m") + std::to_string(exit_status) + "\e[m\n"); + }); + } +} diff --git a/src/project.hpp b/src/project.hpp index 5f37798..ecdb0f7 100644 --- a/src/project.hpp +++ b/src/project.hpp @@ -171,6 +171,15 @@ namespace Project { std::string get_language_id() override { return "go"; } }; + class Julia : public LanguageProtocol { + public: + Julia(std::unique_ptr &&build) : Base(std::move(build)) {} + + void compile_and_run() override; + + std::string get_language_id() override { return "julia"; } + }; + std::shared_ptr create(); extern std::shared_ptr current; }; // namespace Project diff --git a/src/source.cpp b/src/source.cpp index 88a698e..e736550 100644 --- a/src/source.cpp +++ b/src/source.cpp @@ -224,7 +224,8 @@ Source::View::View(const boost::filesystem::path &file_path, const Glib::RefPtr< if(language_id == "cmake" || language_id == "makefile" || language_id == "python" || language_id == "python3" || language_id == "sh" || language_id == "perl" || language_id == "ruby" || language_id == "r" || language_id == "asm" || - language_id == "automake" || language_id == "yaml" || language_id == "docker") + language_id == "automake" || language_id == "yaml" || language_id == "docker" || + language_id == "julia") comment_characters = "#"; else if(language_id == "latex" || language_id == "matlab" || language_id == "octave" || language_id == "bibtex") comment_characters = "%"; diff --git a/src/source_base.cpp b/src/source_base.cpp index eaa94a5..cd955e0 100644 --- a/src/source_base.cpp +++ b/src/source_base.cpp @@ -291,11 +291,12 @@ Source::BaseView::BaseView(const boost::filesystem::path &file_path, const Glib: tab_char = Config::get().source.default_tab_char; tab_size = Config::get().source.default_tab_size; if(language) { - if(language->get_id() == "python" || language->get_id() == "rust") { + auto language_id = language->get_id(); + if(language_id == "python" || language_id == "rust" || language_id == "julia") { tab_char = ' '; tab_size = 4; } - else if(language->get_id() == "go") { + else if(language_id == "go") { tab_char = '\t'; tab_size = 1; } diff --git a/src/source_language_protocol.cpp b/src/source_language_protocol.cpp index cc4e588..e894e00 100644 --- a/src/source_language_protocol.cpp +++ b/src/source_language_protocol.cpp @@ -369,7 +369,7 @@ void LanguageProtocol::Client::write_request(Source::LanguageProtocolView *view, LockGuard lock(timeout_threads_mutex); timeout_threads.emplace_back([this, message_id] { for(size_t c = 0; c < 20; ++c) { - std::this_thread::sleep_for(std::chrono::milliseconds(500)); + std::this_thread::sleep_for(std::chrono::milliseconds(50000) * (language_id == "julia" ? 100 : 1)); LockGuard lock(read_write_mutex); auto id_it = handlers.find(message_id); if(id_it == handlers.end()) diff --git a/src/tooltips.cpp b/src/tooltips.cpp index e433f36..8f2c3eb 100644 --- a/src/tooltips.cpp +++ b/src/tooltips.cpp @@ -155,19 +155,21 @@ void Tooltip::show(bool disregard_drawn, const std::function &on_motion) return true; } - const static std::regex regex("^([^:]+):([^:]+):([^:]+)$", std::regex::optimize); + const static std::regex regex("^([^:]+):([^:]+)(:[^:]+)?$", std::regex::optimize); std::smatch sm; if(std::regex_match(link, sm, regex)) { auto path = boost::filesystem::path(sm[1].str()); - if(auto source_view = dynamic_cast(view)) - path = filesystem::get_normal_path(source_view->file_path.parent_path() / path); + if(path.is_relative()) { + if(auto source_view = dynamic_cast(view)) + path = filesystem::get_normal_path(source_view->file_path.parent_path() / path); + } boost::system::error_code ec; if(boost::filesystem::is_regular_file(path, ec)) { if(Notebook::get().open(path)) { try { auto line = std::stoi(sm[2].str()) - 1; - auto offset = std::stoi(sm[3].str()) - 1; + auto offset = sm.length(3) ? std::stoi(sm[3].str().substr(1)) - 1 : 0; auto view = Notebook::get().get_current_view(); view->place_cursor_at_line_offset(line, offset); view->scroll_to_cursor_delayed(true, false);