From 0a3102f13e62d78a329d488fb1eb8812181e448e Mon Sep 17 00:00:00 2001 From: eidheim Date: Sun, 29 Aug 2021 19:06:25 +0200 Subject: [PATCH] Language client: added pyright workarounds --- src/source_base.cpp | 12 +++++++++++ src/source_base.hpp | 1 + src/source_language_protocol.cpp | 37 +++++++++++++++++++++----------- src/source_language_protocol.hpp | 3 +++ src/tooltips.cpp | 33 ++++++++++++++++++++++++++-- tests/tooltips_test.cpp | 32 +++++++++++++++++++++++++++ 6 files changed, 103 insertions(+), 15 deletions(-) diff --git a/src/source_base.cpp b/src/source_base.cpp index d05d253..565b580 100644 --- a/src/source_base.cpp +++ b/src/source_base.cpp @@ -881,6 +881,18 @@ std::string Source::BaseView::get_token(const Gtk::TextIter &iter) { return get_buffer()->get_text(range.first, range.second); } +std::string Source::BaseView::get_token(const Glib::ustring &string, size_t pos) { + if(pos >= string.size()) + return {}; + auto start = pos; + auto end = pos; + for(auto i = pos - 1; i != Glib::ustring::npos && is_token_char(string[i]); --i) + start = pos; + for(; end < string.size() && is_token_char(string[end]); ++end) { + } + return string.substr(start, end - start); +} + void Source::BaseView::cleanup_whitespace_characters() { auto buffer = get_buffer(); buffer->begin_user_action(); diff --git a/src/source_base.hpp b/src/source_base.hpp index ba6ee2c..2cb482c 100644 --- a/src/source_base.hpp +++ b/src/source_base.hpp @@ -176,6 +176,7 @@ namespace Source { protected: std::pair get_token_iters(Gtk::TextIter iter); std::string get_token(const Gtk::TextIter &iter); + std::string get_token(const Glib::ustring &string, size_t pos = 0); void cleanup_whitespace_characters(); void cleanup_whitespace_characters(const Gtk::TextIter &iter); diff --git a/src/source_language_protocol.cpp b/src/source_language_protocol.cpp index 9411c1d..0d20521 100644 --- a/src/source_language_protocol.cpp +++ b/src/source_language_protocol.cpp @@ -546,6 +546,14 @@ void LanguageProtocol::Client::handle_server_notification(const std::string &met } } } + else if(method == "window/logMessage") { + if(language_id == "python" && !pyright) { + if(auto message = params.string_optional("message")) { + if(starts_with(*message, "Pyright language server")) + pyright = true; + } + } + } } void LanguageProtocol::Client::handle_server_request(const boost::variant &id, const std::string &method, JSON &¶ms) { @@ -624,7 +632,7 @@ void LanguageProtocol::Client::handle_server_request(const boost::variantpost([this] { LockGuard lock(views_mutex); for(auto &view : views) { @@ -1707,7 +1715,7 @@ void Source::LanguageProtocolView::setup_autocomplete() { if(parameter_position == current_parameter_position || using_named_parameters) { auto label = parameter.string_or("label", ""); auto insert = label; - if(!using_named_parameters || used_named_parameters.find(insert) == used_named_parameters.end()) { + if(!using_named_parameters || used_named_parameters.find(get_token(insert)) == used_named_parameters.end()) { autocomplete->rows.emplace_back(std::move(label)); autocomplete_rows.emplace_back(AutocompleteRow{std::move(insert), {}, LanguageProtocol::Documentation(parameter.child_optional("documentation")), {}, {}}); } @@ -1772,7 +1780,7 @@ void Source::LanguageProtocolView::setup_autocomplete() { insert += "(${1:})"; std::shared_ptr item_object; - if(detail.empty() && documentation.value.empty() && (is_incomplete || is_js || language_id == "python")) // Workaround for typescript-language-server (is_js) and python-lsp-server + if(detail.empty() && documentation.value.empty() && (is_incomplete || is_js || (language_id == "python" && !client->pyright))) // Workaround for typescript-language-server (is_js) and python-lsp-server item_object = std::make_shared(JSON::make_owner(std::move(item))); autocomplete->rows.emplace_back(std::move(label)); @@ -1837,14 +1845,17 @@ void Source::LanguageProtocolView::setup_autocomplete() { if(hide_window) { if(autocomplete_show_arguments) { - if(auto symbol = get_named_parameter_symbol()) // Do not select named parameters in for instance Python - get_buffer()->insert(CompletionDialog::get()->start_mark->get_iter(), insert + *symbol); - else { - get_buffer()->insert(CompletionDialog::get()->start_mark->get_iter(), insert); - int start_offset = CompletionDialog::get()->start_mark->get_iter().get_offset(); - int end_offset = CompletionDialog::get()->start_mark->get_iter().get_offset() + insert.size(); - get_buffer()->select_range(get_buffer()->get_iter_at_offset(start_offset), get_buffer()->get_iter_at_offset(end_offset)); + if(auto symbol = get_named_parameter_symbol()) { // Do not select named parameters in for instance Python + auto named_parameter = get_token(insert); + if(!named_parameter.empty()) { + get_buffer()->insert(CompletionDialog::get()->start_mark->get_iter(), named_parameter + *symbol); + return; + } } + get_buffer()->insert(CompletionDialog::get()->start_mark->get_iter(), insert); + int start_offset = CompletionDialog::get()->start_mark->get_iter().get_offset(); + int end_offset = CompletionDialog::get()->start_mark->get_iter().get_offset() + insert.size(); + get_buffer()->select_range(get_buffer()->get_iter_at_offset(start_offset), get_buffer()->get_iter_at_offset(end_offset)); return; } @@ -1878,7 +1889,7 @@ void Source::LanguageProtocolView::setup_autocomplete() { auto &autocomplete_row = autocomplete_rows[index]; const static auto insert_documentation = [](Source::LanguageProtocolView *view, Tooltip &tooltip, const std::string &detail, const LanguageProtocol::Documentation &documentation) { - if(view->language_id == "python") // Python might support markdown in the future + if(view->language_id == "python" && !view->client->pyright) // pylsp might support markdown in the future tooltip.insert_docstring(documentation.value); else { if(!detail.empty()) { @@ -2082,7 +2093,7 @@ void Source::LanguageProtocolView::update_diagnostics(std::vectorpyright) { // pylsp might support markdown in the future tooltip.insert_with_links_tagged(diagnostic.message); return; } @@ -2206,7 +2217,7 @@ void Source::LanguageProtocolView::show_type_tooltips(const Gdk::Rectangle &rect auto token_iters = get_token_iters(get_buffer()->get_iter_at_offset(offset)); type_tooltips.emplace_back(this, token_iters.first, token_iters.second, [this, offset, contents = std::move(contents)](Tooltip &tooltip) mutable { bool first = true; - if(language_id == "python") { // Python might support markdown in the future + if(language_id == "python" && !client->pyright) { // pylsp might support markdown in the future for(auto &content : contents) { if(!first) tooltip.buffer->insert_at_cursor("\n\n"); diff --git a/src/source_language_protocol.hpp b/src/source_language_protocol.hpp index f1d3311..f2ad596 100644 --- a/src/source_language_protocol.hpp +++ b/src/source_language_protocol.hpp @@ -193,6 +193,9 @@ namespace LanguageProtocol { void handle_server_request(const boost::variant &id, const std::string &method, JSON &¶ms); std::function on_exit_status; + + /// Detecting pyright language server since workarounds need to be applied + std::atomic pyright = {false}; }; } // namespace LanguageProtocol diff --git a/src/tooltips.cpp b/src/tooltips.cpp index e52bd05..caceb8d 100644 --- a/src/tooltips.cpp +++ b/src/tooltips.cpp @@ -729,7 +729,16 @@ void Tooltip::insert_markdown(const std::string &input) { }; for(; i < to; i++) { - if(!unescape(i) && (insert_code() || insert_emphasis() || insert_strikethrough() || insert_link())) + if(unescape(i)) { + partial += input[i]; + continue; + } + else if(starts_with(input, i, " ")) { + partial += ' '; + i += 5; + continue; + } + else if(insert_code() || insert_emphasis() || insert_strikethrough() || insert_link()) continue; if(input[i] == '\n' && i + 1 < to) partial += ' '; @@ -792,6 +801,26 @@ void Tooltip::insert_markdown(const std::string &input) { return false; }; + auto insert_horizontal_line = [&] { + auto i_saved = i; + char symbol = 0; + if(starts_with(input, i, "---") || starts_with(input, i, "***") || starts_with(input, i, "___")) + symbol = input[i]; + if(symbol != 0) { + forward_passed({symbol}); + if(i == input.size() || input[i] == '\n') { + if(i < input.size()) + ++i; + buffer->insert_at_cursor("---\n"); + if(is_empty_line()) + buffer->insert_at_cursor("\n"); + return true; + } + } + i = i_saved; + return false; + }; + auto insert_code_block = [&] { if(starts_with(input, i, "```")) { auto i_saved = i; @@ -907,7 +936,7 @@ void Tooltip::insert_markdown(const std::string &input) { }; while(forward_passed_empty_line()) { - if(insert_header() || insert_code_block() || insert_reference() || insert_list()) + if(insert_header() || insert_horizontal_line() || insert_code_block() || insert_reference() || insert_list()) continue; // Insert paragraph: auto start = i; diff --git a/tests/tooltips_test.cpp b/tests/tooltips_test.cpp index fdf2946..6a04118 100644 --- a/tests/tooltips_test.cpp +++ b/tests/tooltips_test.cpp @@ -57,6 +57,38 @@ int main() { auto buffer = tooltip->buffer; g_assert(buffer->get_text() == "# test"); } + { + auto tooltip = get_markdown_tooltip("test\\\ntest"); + g_assert(tooltip->buffer->get_text() == "test\ntest"); + } + { + auto tooltip = get_markdown_tooltip("test  test"); + g_assert(tooltip->buffer->get_text() == "test test"); + } + { + auto tooltip = get_markdown_tooltip("test\n\n---\ntest"); + g_assert(tooltip->buffer->get_text() == "test\n\n---\ntest"); + } + { + auto tooltip = get_markdown_tooltip("test\n\n-----\ntest"); + g_assert(tooltip->buffer->get_text() == "test\n\n---\ntest"); + } + { + auto tooltip = get_markdown_tooltip("test\n\n***\n\ntest"); + g_assert(tooltip->buffer->get_text() == "test\n\n---\n\ntest"); + } + { + auto tooltip = get_markdown_tooltip("test\n\n___\n\ntest"); + g_assert(tooltip->buffer->get_text() == "test\n\n---\n\ntest"); + } + { + auto tooltip = get_markdown_tooltip("test\n\n---\n\ntest"); + g_assert(tooltip->buffer->get_text() == "test\n\n---\n\ntest"); + } + { + auto tooltip = get_markdown_tooltip("test\n\n---test---\n\ntest"); + g_assert(tooltip->buffer->get_text() == "test\n\n---test---\n\ntest"); + } { auto tooltip = get_markdown_tooltip("# test"); auto buffer = tooltip->buffer;