Browse Source

Language client: added support for type declaration and implementation location. Also fixes to utf-8 byte count and regular utf-16 offsets, and cleaned up write_request and write_notification calls

pipelines/353213535
eidheim 5 years ago
parent
commit
70d9818772
  1. 10
      src/autocomplete.cpp
  2. 3
      src/autocomplete.hpp
  3. 4
      src/source_clang.cpp
  4. 2
      src/source_generic.cpp
  5. 1659
      src/source_language_protocol.cpp
  6. 33
      src/source_language_protocol.hpp
  7. 40
      src/utility.cpp
  8. 2
      src/utility.hpp
  9. 19
      tests/utility_test.cpp

10
src/autocomplete.cpp

@ -59,19 +59,19 @@ void Autocomplete::run() {
if(thread.joinable()) if(thread.joinable())
thread.join(); thread.join();
auto iter = view->get_buffer()->get_insert()->get_iter(); auto iter = view->get_buffer()->get_insert()->get_iter();
auto line_nr = iter.get_line() + 1; auto line = iter.get_line();
auto column_nr = iter.get_line_index() + 1; auto line_index = iter.get_line_index();
Glib::ustring buffer; Glib::ustring buffer;
if(pass_buffer_and_strip_word) { if(pass_buffer_and_strip_word) {
auto pos = iter.get_offset() - 1; auto pos = iter.get_offset() - 1;
buffer = view->get_buffer()->get_text(); buffer = view->get_buffer()->get_text();
while(pos >= 0 && Source::BaseView::is_token_char(buffer[pos])) { while(pos >= 0 && Source::BaseView::is_token_char(buffer[pos])) {
buffer.replace(pos, 1, " "); buffer.replace(pos, 1, " ");
column_nr--; line_index--;
pos--; pos--;
} }
} }
thread = std::thread([this, line_nr, column_nr, buffer = std::move(buffer)] { thread = std::thread([this, line, line_index, buffer = std::move(buffer)] {
auto lock = get_parse_lock(); auto lock = get_parse_lock();
if(!is_processing()) if(!is_processing())
return; return;
@ -79,7 +79,7 @@ void Autocomplete::run() {
rows.clear(); rows.clear();
auto &buffer_raw = const_cast<std::string &>(buffer.raw()); auto &buffer_raw = const_cast<std::string &>(buffer.raw());
bool success = add_rows(buffer_raw, line_nr, column_nr); bool success = add_rows(buffer_raw, line, line_index);
if(!is_processing()) if(!is_processing())
return; return;

3
src/autocomplete.hpp

@ -48,7 +48,8 @@ public:
std::function<void()> on_add_rows_error = [] {}; std::function<void()> on_add_rows_error = [] {};
/// The handler is not run in the main loop. Should return false on error. /// The handler is not run in the main loop. Should return false on error.
std::function<bool(std::string &buffer, int line_number, int column)> add_rows = [](std::string &, int, int) { return true; }; /// Column is line byte index.
std::function<bool(std::string &buffer, int line, int line_index)> add_rows = [](std::string &, int, int) { return true; };
std::function<void()> on_show = [] {}; std::function<void()> on_show = [] {};
std::function<void()> on_hide = [] {}; std::function<void()> on_hide = [] {};

4
src/source_clang.cpp

@ -948,10 +948,10 @@ Source::ClangViewAutocomplete::ClangViewAutocomplete(const boost::filesystem::pa
full_reparse(); full_reparse();
}; };
autocomplete.add_rows = [this](std::string &buffer, int line_number, int column) { autocomplete.add_rows = [this](std::string &buffer, int line, int line_index) {
if(is_language({"chdr", "cpphdr"})) if(is_language({"chdr", "cpphdr"}))
clangmm::remove_include_guard(buffer); clangmm::remove_include_guard(buffer);
code_complete_results = std::make_unique<clangmm::CodeCompleteResults>(clang_tu->get_code_completions(buffer, line_number, column)); code_complete_results = std::make_unique<clangmm::CodeCompleteResults>(clang_tu->get_code_completions(buffer, line + 1, line_index + 1));
if(!code_complete_results->cx_results) if(!code_complete_results->cx_results)
return false; return false;

2
src/source_generic.cpp

@ -243,7 +243,7 @@ void Source::GenericView::setup_autocomplete() {
update_status_state(this); update_status_state(this);
}; };
autocomplete.add_rows = [this](std::string &buffer, int line_number, int column) { autocomplete.add_rows = [this](std::string &buffer, int /*line*/, int /*line_index*/) {
if(autocomplete.state == Autocomplete::State::starting) { if(autocomplete.state == Autocomplete::State::starting) {
autocomplete_comment.clear(); autocomplete_comment.clear();
autocomplete_insert.clear(); autocomplete_insert.clear();

1659
src/source_language_protocol.cpp

File diff suppressed because it is too large Load Diff

33
src/source_language_protocol.hpp

@ -101,6 +101,8 @@ namespace LanguageProtocol {
bool completion = false; bool completion = false;
bool signature_help = false; bool signature_help = false;
bool definition = false; bool definition = false;
bool type_definition = false;
bool implementation = false;
bool references = false; bool references = false;
bool document_highlight = false; bool document_highlight = false;
bool workspace_symbol = false; bool workspace_symbol = false;
@ -155,7 +157,7 @@ namespace LanguageProtocol {
void parse_server_message(); void parse_server_message();
void write_request(Source::LanguageProtocolView *view, const std::string &method, const std::string &params, std::function<void(const boost::property_tree::ptree &, bool)> &&function = nullptr); void write_request(Source::LanguageProtocolView *view, const std::string &method, const std::string &params, std::function<void(const boost::property_tree::ptree &, bool)> &&function = nullptr);
void write_response(size_t id, const std::string &result); void write_response(size_t id, const std::string &result);
void write_notification(const std::string &method, const std::string &params); void write_notification(const std::string &method, const std::string &params = {});
void handle_server_notification(const std::string &method, const boost::property_tree::ptree &params); void handle_server_notification(const std::string &method, const boost::property_tree::ptree &params);
void handle_server_request(size_t id, const std::string &method, const boost::property_tree::ptree &params); void handle_server_request(size_t id, const std::string &method, const boost::property_tree::ptree &params);
@ -174,14 +176,31 @@ namespace Source {
void rename(const boost::filesystem::path &path) override; void rename(const boost::filesystem::path &path) override;
bool save() override; bool save() override;
void update_diagnostics_async(std::vector<LanguageProtocol::Diagnostic> &&diagnostics);
private: private:
std::atomic<size_t> update_diagnostics_async_count = {0}; /// Get line offset depending on if utf-8 byte offsets or utf-16 code units are used
int get_line_pos(const Gtk::TextIter &iter);
/// Get line offset depending on if utf-8 byte offsets or utf-16 code units are used
int get_line_pos(int line, int line_index);
std::pair<std::string, std::string> make_position(int line, int character);
std::pair<std::string, std::string> make_range(const std::pair<int, int> &start, const std::pair<int, int> &end);
std::string to_string(const std::pair<std::string, std::string> &param);
std::string to_string(const std::vector<std::pair<std::string, std::string>> &params);
/// Helper method for calling client->write_request
void write_request(const std::string &method, const std::vector<std::pair<std::string, std::string>> &params, std::function<void(const boost::property_tree::ptree &, bool)> &&function);
/// Helper method for calling client->write_notification
void write_notification(const std::string &method);
/// Helper method for calling client->write_notification
void write_did_open_notification();
/// Helper method for calling client->write_notification
void write_did_change_notification(const std::vector<std::pair<std::string, std::string>> &params);
std::atomic<size_t> update_diagnostics_async_count = {0};
void update_diagnostics(std::vector<LanguageProtocol::Diagnostic> diagnostics); void update_diagnostics(std::vector<LanguageProtocol::Diagnostic> diagnostics);
public: public:
void update_diagnostics_async(std::vector<LanguageProtocol::Diagnostic> &&diagnostics);
Gtk::TextIter get_iter_at_line_pos(int line, int pos) override; Gtk::TextIter get_iter_at_line_pos(int line, int pos) override;
std::string uri; std::string uri;
@ -208,14 +227,16 @@ namespace Source {
Glib::ThreadPool thread_pool; Glib::ThreadPool thread_pool;
void setup_navigation_and_refactoring(); void setup_navigation_and_refactoring();
void setup_signals();
void setup_autocomplete();
void tag_similar_symbols(); void tag_similar_symbols();
Offset get_declaration(const Gtk::TextIter &iter); Offset get_declaration(const Gtk::TextIter &iter);
Offset get_type_declaration(const Gtk::TextIter &iter);
std::vector<Offset> get_implementations(const Gtk::TextIter &iter);
std::unique_ptr<Autocomplete> autocomplete; std::unique_ptr<Autocomplete> autocomplete;
void setup_signals();
void setup_autocomplete();
struct AutocompleteRow { struct AutocompleteRow {
std::string insert; std::string insert;

40
src/utility.cpp

@ -7,31 +7,31 @@ ScopeGuard::~ScopeGuard() {
} }
size_t utf8_character_count(const std::string &text, size_t pos, size_t length) noexcept { size_t utf8_character_count(const std::string &text, size_t pos, size_t length) noexcept {
size_t count = 0; size_t characters = 0;
auto size = length == std::string::npos ? text.size() : std::min(pos + length, text.size()); auto size = length == std::string::npos ? text.size() : std::min(pos + length, text.size());
for(; pos < size;) { for(; pos < size;) {
if(static_cast<unsigned char>(text[pos]) <= 0b01111111) { if(static_cast<unsigned char>(text[pos]) <= 0b01111111) {
++count; ++characters;
++pos; ++pos;
} }
else if(static_cast<unsigned char>(text[pos]) >= 0b11111000) // Invalid UTF-8 byte else if(static_cast<unsigned char>(text[pos]) >= 0b11111000) // Invalid UTF-8 byte
++pos; ++pos;
else if(static_cast<unsigned char>(text[pos]) >= 0b11110000) { else if(static_cast<unsigned char>(text[pos]) >= 0b11110000) {
++count; ++characters;
pos += 4; pos += 4;
} }
else if(static_cast<unsigned char>(text[pos]) >= 0b11100000) { else if(static_cast<unsigned char>(text[pos]) >= 0b11100000) {
++count; ++characters;
pos += 3; pos += 3;
} }
else if(static_cast<unsigned char>(text[pos]) >= 0b11000000) { else if(static_cast<unsigned char>(text[pos]) >= 0b11000000) {
++count; ++characters;
pos += 2; pos += 2;
} }
else // // Invalid start of UTF-8 character else // // Invalid start of UTF-8 character
++pos; ++pos;
} }
return count; return characters;
} }
size_t utf16_code_units_byte_count(const std::string &text, size_t code_units, size_t start_pos) { size_t utf16_code_units_byte_count(const std::string &text, size_t code_units, size_t start_pos) {
@ -73,6 +73,34 @@ size_t utf16_code_units_byte_count(const std::string &text, size_t code_units, s
return pos - start_pos; return pos - start_pos;
} }
size_t utf16_code_unit_count(const std::string &text, size_t pos, size_t length) {
size_t code_units = 0;
auto size = length == std::string::npos ? text.size() : std::min(pos + length, text.size());
for(; pos < size;) {
if(static_cast<unsigned char>(text[pos]) <= 0b01111111) {
++code_units;
++pos;
}
else if(static_cast<unsigned char>(text[pos]) >= 0b11111000) // Invalid UTF-8 byte
++pos;
else if(static_cast<unsigned char>(text[pos]) >= 0b11110000) {
code_units += 2;
pos += 4;
}
else if(static_cast<unsigned char>(text[pos]) >= 0b11100000) {
++code_units;
pos += 3;
}
else if(static_cast<unsigned char>(text[pos]) >= 0b11000000) {
++code_units;
pos += 2;
}
else // // Invalid start of UTF-8 character
++pos;
}
return code_units;
}
bool starts_with(const char *str, const std::string &test) noexcept { bool starts_with(const char *str, const std::string &test) noexcept {
for(size_t i = 0; i < test.size(); ++i) { for(size_t i = 0; i < test.size(); ++i) {
if(*str == '\0') if(*str == '\0')

2
src/utility.hpp

@ -13,6 +13,8 @@ size_t utf8_character_count(const std::string &text, size_t pos = 0, size_t leng
/// Returns number of bytes in the given utf16 code units in text /// Returns number of bytes in the given utf16 code units in text
size_t utf16_code_units_byte_count(const std::string &text, size_t code_units, size_t start_pos = 0); size_t utf16_code_units_byte_count(const std::string &text, size_t code_units, size_t start_pos = 0);
/// Returns number of utf16 code units in the text
size_t utf16_code_unit_count(const std::string &text, size_t pos = 0, size_t length = std::string::npos);
bool starts_with(const char *str, const std::string &test) noexcept; bool starts_with(const char *str, const std::string &test) noexcept;
bool starts_with(const char *str, const char *test) noexcept; bool starts_with(const char *str, const char *test) noexcept;

19
tests/utility_test.cpp

@ -50,6 +50,25 @@ int main() {
g_assert_cmpuint(utf16_code_units_byte_count("test🔥test", 10), ==, 12); // Fire emoji between test words g_assert_cmpuint(utf16_code_units_byte_count("test🔥test", 10), ==, 12); // Fire emoji between test words
g_assert_cmpuint(utf16_code_units_byte_count("test🔥test", 11), ==, 12); // Fire emoji between test words g_assert_cmpuint(utf16_code_units_byte_count("test🔥test", 11), ==, 12); // Fire emoji between test words
g_assert_cmpuint(utf16_code_unit_count("", 0, 0), ==, 0);
g_assert_cmpuint(utf16_code_unit_count("", 0, 2), ==, 0);
g_assert_cmpuint(utf16_code_unit_count("", 2, 2), ==, 0);
g_assert_cmpuint(utf16_code_unit_count("test", 0, 1), ==, 1);
g_assert_cmpuint(utf16_code_unit_count("test", 0, 4), ==, 4);
g_assert_cmpuint(utf16_code_unit_count("test", 0, 10), ==, 4);
g_assert_cmpuint(utf16_code_unit_count("test", 2, 2), ==, 2);
g_assert_cmpuint(utf16_code_unit_count("æøå", 0, 0), ==, 0);
g_assert_cmpuint(utf16_code_unit_count("æøå", 0, 2), ==, 1);
g_assert_cmpuint(utf16_code_unit_count("æøå", 0, 4), ==, 2);
g_assert_cmpuint(utf16_code_unit_count("æøå", 0, 6), ==, 3);
g_assert_cmpuint(utf16_code_unit_count("æøå", 2, 6), ==, 2);
g_assert_cmpuint(utf16_code_unit_count("æøå", 4, 6), ==, 1);
g_assert_cmpuint(utf16_code_unit_count("æøå", 6, 6), ==, 0);
g_assert_cmpuint(utf16_code_unit_count("test🔥test", 0, 0), ==, 0); // Fire emoji between test words
g_assert_cmpuint(utf16_code_unit_count("test🔥test", 0, 4), ==, 4); // Fire emoji between test words
g_assert_cmpuint(utf16_code_unit_count("test🔥test", 0, 8), ==, 6); // Fire emoji between test words
g_assert_cmpuint(utf16_code_unit_count("test🔥test", 0, 12), ==, 10); // Fire emoji between test words
std::string empty; std::string empty;
std::string test("test"); std::string test("test");
std::string testtest("testtest"); std::string testtest("testtest");

Loading…
Cancel
Save