Browse Source

Language client: added pyright workarounds

merge-requests/409/head
eidheim 4 years ago
parent
commit
0a3102f13e
  1. 12
      src/source_base.cpp
  2. 1
      src/source_base.hpp
  3. 31
      src/source_language_protocol.cpp
  4. 3
      src/source_language_protocol.hpp
  5. 33
      src/tooltips.cpp
  6. 32
      tests/tooltips_test.cpp

12
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); 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() { void Source::BaseView::cleanup_whitespace_characters() {
auto buffer = get_buffer(); auto buffer = get_buffer();
buffer->begin_user_action(); buffer->begin_user_action();

1
src/source_base.hpp

@ -176,6 +176,7 @@ namespace Source {
protected: protected:
std::pair<Gtk::TextIter, Gtk::TextIter> get_token_iters(Gtk::TextIter iter); std::pair<Gtk::TextIter, Gtk::TextIter> get_token_iters(Gtk::TextIter iter);
std::string get_token(const 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();
void cleanup_whitespace_characters(const Gtk::TextIter &iter); void cleanup_whitespace_characters(const Gtk::TextIter &iter);

31
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<size_t, std::string> &id, const std::string &method, JSON &&params) { void LanguageProtocol::Client::handle_server_request(const boost::variant<size_t, std::string> &id, const std::string &method, JSON &&params) {
@ -624,7 +632,7 @@ void LanguageProtocol::Client::handle_server_request(const boost::variant<size_t
for(auto &registration : params.array("registrations")) { for(auto &registration : params.array("registrations")) {
if(registration.string("method") == "workspace/didChangeWorkspaceFolders") { if(registration.string("method") == "workspace/didChangeWorkspaceFolders") {
write_notification("workspace/didChangeWorkspaceFolders", "\"event\":{\"added\":[{\"uri\": \"" + JSON::escape_string(filesystem::get_uri_from_path(root_path)) + "\",\"name\":\"" + JSON::escape_string(root_path.filename().string()) + "\"}],\"removed\":[]}"); write_notification("workspace/didChangeWorkspaceFolders", "\"event\":{\"added\":[{\"uri\": \"" + JSON::escape_string(filesystem::get_uri_from_path(root_path)) + "\",\"name\":\"" + JSON::escape_string(root_path.filename().string()) + "\"}],\"removed\":[]}");
if(language_id == "python") { // Workaround for pyright if(pyright) {
dispatcher->post([this] { dispatcher->post([this] {
LockGuard lock(views_mutex); LockGuard lock(views_mutex);
for(auto &view : views) { for(auto &view : views) {
@ -1707,7 +1715,7 @@ void Source::LanguageProtocolView::setup_autocomplete() {
if(parameter_position == current_parameter_position || using_named_parameters) { if(parameter_position == current_parameter_position || using_named_parameters) {
auto label = parameter.string_or("label", ""); auto label = parameter.string_or("label", "");
auto insert = 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(std::move(label));
autocomplete_rows.emplace_back(AutocompleteRow{std::move(insert), {}, LanguageProtocol::Documentation(parameter.child_optional("documentation")), {}, {}}); 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:})"; insert += "(${1:})";
std::shared_ptr<JSON> item_object; std::shared_ptr<JSON> 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>(JSON::make_owner(std::move(item))); item_object = std::make_shared<JSON>(JSON::make_owner(std::move(item)));
autocomplete->rows.emplace_back(std::move(label)); autocomplete->rows.emplace_back(std::move(label));
@ -1837,14 +1845,17 @@ void Source::LanguageProtocolView::setup_autocomplete() {
if(hide_window) { if(hide_window) {
if(autocomplete_show_arguments) { if(autocomplete_show_arguments) {
if(auto symbol = get_named_parameter_symbol()) // Do not select named parameters in for instance Python 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); auto named_parameter = get_token(insert);
else { 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); get_buffer()->insert(CompletionDialog::get()->start_mark->get_iter(), insert);
int start_offset = CompletionDialog::get()->start_mark->get_iter().get_offset(); int start_offset = CompletionDialog::get()->start_mark->get_iter().get_offset();
int end_offset = CompletionDialog::get()->start_mark->get_iter().get_offset() + insert.size(); 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)); get_buffer()->select_range(get_buffer()->get_iter_at_offset(start_offset), get_buffer()->get_iter_at_offset(end_offset));
}
return; return;
} }
@ -1878,7 +1889,7 @@ void Source::LanguageProtocolView::setup_autocomplete() {
auto &autocomplete_row = autocomplete_rows[index]; auto &autocomplete_row = autocomplete_rows[index];
const static auto insert_documentation = [](Source::LanguageProtocolView *view, Tooltip &tooltip, const std::string &detail, const LanguageProtocol::Documentation &documentation) { 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); tooltip.insert_docstring(documentation.value);
else { else {
if(!detail.empty()) { if(!detail.empty()) {
@ -2082,7 +2093,7 @@ void Source::LanguageProtocolView::update_diagnostics(std::vector<LanguageProtoc
fix_its.insert(fix_its.end(), quickfix.second.begin(), quickfix.second.end()); fix_its.insert(fix_its.end(), quickfix.second.begin(), quickfix.second.end());
add_diagnostic_tooltip(start, end, error, [this, diagnostic = std::move(diagnostic)](Tooltip &tooltip) { add_diagnostic_tooltip(start, end, error, [this, diagnostic = std::move(diagnostic)](Tooltip &tooltip) {
if(language_id == "python") { // Python might support markdown in the future if(language_id == "python" && !client->pyright) { // pylsp might support markdown in the future
tooltip.insert_with_links_tagged(diagnostic.message); tooltip.insert_with_links_tagged(diagnostic.message);
return; 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)); 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 { type_tooltips.emplace_back(this, token_iters.first, token_iters.second, [this, offset, contents = std::move(contents)](Tooltip &tooltip) mutable {
bool first = true; 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) { for(auto &content : contents) {
if(!first) if(!first)
tooltip.buffer->insert_at_cursor("\n\n"); tooltip.buffer->insert_at_cursor("\n\n");

3
src/source_language_protocol.hpp

@ -193,6 +193,9 @@ namespace LanguageProtocol {
void handle_server_request(const boost::variant<size_t, std::string> &id, const std::string &method, JSON &&params); void handle_server_request(const boost::variant<size_t, std::string> &id, const std::string &method, JSON &&params);
std::function<void(int exit_status)> on_exit_status; std::function<void(int exit_status)> on_exit_status;
/// Detecting pyright language server since workarounds need to be applied
std::atomic<bool> pyright = {false};
}; };
} // namespace LanguageProtocol } // namespace LanguageProtocol

33
src/tooltips.cpp

@ -729,7 +729,16 @@ void Tooltip::insert_markdown(const std::string &input) {
}; };
for(; i < to; i++) { 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, "&nbsp;")) {
partial += ' ';
i += 5;
continue;
}
else if(insert_code() || insert_emphasis() || insert_strikethrough() || insert_link())
continue; continue;
if(input[i] == '\n' && i + 1 < to) if(input[i] == '\n' && i + 1 < to)
partial += ' '; partial += ' ';
@ -792,6 +801,26 @@ void Tooltip::insert_markdown(const std::string &input) {
return false; 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 = [&] { auto insert_code_block = [&] {
if(starts_with(input, i, "```")) { if(starts_with(input, i, "```")) {
auto i_saved = i; auto i_saved = i;
@ -907,7 +936,7 @@ void Tooltip::insert_markdown(const std::string &input) {
}; };
while(forward_passed_empty_line()) { 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; continue;
// Insert paragraph: // Insert paragraph:
auto start = i; auto start = i;

32
tests/tooltips_test.cpp

@ -57,6 +57,38 @@ int main() {
auto buffer = tooltip->buffer; auto buffer = tooltip->buffer;
g_assert(buffer->get_text() == "# test"); 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&nbsp;&nbsp;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 tooltip = get_markdown_tooltip("# test");
auto buffer = tooltip->buffer; auto buffer = tooltip->buffer;

Loading…
Cancel
Save