diff --git a/src/source.cc b/src/source.cc index 18529e6..48a9f57 100644 --- a/src/source.cc +++ b/src/source.cc @@ -119,6 +119,9 @@ Source::View::View(const boost::filesystem::path &file_path, const Glib::RefPtr< similar_symbol_tag = get_buffer()->create_tag(); similar_symbol_tag->property_weight() = Pango::WEIGHT_ULTRAHEAVY; + clickable_tag = get_buffer()->create_tag(); + clickable_tag->property_underline() = Pango::Underline::UNDERLINE_SINGLE; + clickable_tag->property_underline_set() = true; get_buffer()->create_tag("def:warning"); get_buffer()->create_tag("def:warning_underline"); @@ -148,23 +151,6 @@ Source::View::View(const boost::filesystem::path &file_path, const Glib::RefPtr< link_tag = get_buffer()->create_tag("link"); - get_buffer()->signal_changed().connect([this]() { - if(update_status_location) - update_status_location(this); - }); - - signal_realize().connect([this] { - auto gutter = get_gutter(Gtk::TextWindowType::TEXT_WINDOW_LEFT); - auto renderer = gutter->get_renderer_at_pos(15, 0); - if(renderer) { - renderer_activate_connection.disconnect(); - renderer_activate_connection = renderer->signal_activate().connect([this](const Gtk::TextIter &iter, const Gdk::Rectangle &, GdkEvent *) { - if(toggle_breakpoint) - toggle_breakpoint(iter.get_line()); - }); - } - }); - if(language) { auto language_id = language->get_id(); if(language_id == "chdr" || language_id == "cpphdr" || language_id == "c" || language_id == "cpp") { @@ -201,7 +187,7 @@ Source::View::View(const boost::filesystem::path &file_path, const Glib::RefPtr< } } - setup_tooltip_and_dialog_events(); + setup_signals(); setup_format_style(is_generic_view); std::string comment_characters; @@ -455,7 +441,35 @@ void Source::View::configure() { } } -void Source::View::setup_tooltip_and_dialog_events() { +void Source::View::setup_signals() { + get_buffer()->signal_changed().connect([this]() { + if(update_status_location) + update_status_location(this); + + hide_tooltips(); + + if(similar_symbol_tag_applied) { + get_buffer()->remove_tag(similar_symbol_tag, get_buffer()->begin(), get_buffer()->end()); + similar_symbol_tag_applied = false; + } + if(clickable_tag_applied) { + get_buffer()->remove_tag(clickable_tag, get_buffer()->begin(), get_buffer()->end()); + clickable_tag_applied = false; + } + }); + + signal_realize().connect([this] { + auto gutter = get_gutter(Gtk::TextWindowType::TEXT_WINDOW_LEFT); + auto renderer = gutter->get_renderer_at_pos(15, 0); + if(renderer) { + renderer_activate_connection.disconnect(); + renderer_activate_connection = renderer->signal_activate().connect([this](const Gtk::TextIter &iter, const Gdk::Rectangle &, GdkEvent *) { + if(toggle_breakpoint) + toggle_breakpoint(iter.get_line()); + }); + } + }); + type_tooltips.on_motion = [this] { delayed_tooltips_connection.disconnect(); }; @@ -463,10 +477,6 @@ void Source::View::setup_tooltip_and_dialog_events() { delayed_tooltips_connection.disconnect(); }; - get_buffer()->signal_changed().connect([this] { - hide_tooltips(); - }); - signal_motion_notify_event().connect([this](GdkEventMotion *event) { if(on_motion_last_x != event->x || on_motion_last_y != event->y) { delayed_tooltips_connection.disconnect(); @@ -485,6 +495,24 @@ void Source::View::setup_tooltip_and_dialog_events() { return false; }, 100); } + + if(clickable_tag_applied) { + get_buffer()->remove_tag(clickable_tag, get_buffer()->begin(), get_buffer()->end()); + clickable_tag_applied = false; + } + if((event->state & primary_modifier_mask) && !(event->state & GDK_SHIFT_MASK) && !(event->state & GDK_BUTTON1_MASK)) { + delayed_tag_clickable_connection.disconnect(); + delayed_tag_clickable_connection = Glib::signal_timeout().connect([this, x = event->x, y = event->y]() { + int buffer_x, buffer_y; + window_to_buffer_coords(Gtk::TextWindowType::TEXT_WINDOW_TEXT, x, y, buffer_x, buffer_y); + Gtk::TextIter iter; + get_iter_at_location(iter, buffer_x, buffer_y); + apply_clickable_tag(iter); + clickable_tag_applied = true; + return false; + }, 100); + } + auto last_mouse_pos = std::make_pair(on_motion_last_x, on_motion_last_y); auto mouse_pos = std::make_pair(event->x, event->y); type_tooltips.hide(last_mouse_pos, mouse_pos); @@ -501,6 +529,7 @@ void Source::View::setup_tooltip_and_dialog_events() { if(mark->get_name() == "insert") { hide_tooltips(); + delayed_tooltips_connection.disconnect(); delayed_tooltips_connection = Glib::signal_timeout().connect([this]() { Tooltips::init(); @@ -518,6 +547,13 @@ void Source::View::setup_tooltip_and_dialog_events() { return false; }, 500); + delayed_tag_similar_symbols_connection.disconnect(); + delayed_tag_similar_symbols_connection = Glib::signal_timeout().connect([this] { + apply_similar_symbol_tag(); + similar_symbol_tag_applied = true; + return false; + }, 100); + if(SelectionDialog::get()) SelectionDialog::get()->hide(); if(CompletionDialog::get()) @@ -528,6 +564,14 @@ void Source::View::setup_tooltip_and_dialog_events() { } }); + signal_key_release_event().connect([this](GdkEventKey *event) { + if((event->state & primary_modifier_mask) && clickable_tag_applied) { + get_buffer()->remove_tag(clickable_tag, get_buffer()->begin(), get_buffer()->end()); + clickable_tag_applied = false; + } + return false; + }); + signal_scroll_event().connect([this](GdkEventScroll *event) { hide_tooltips(); hide_dialogs(); @@ -536,6 +580,10 @@ void Source::View::setup_tooltip_and_dialog_events() { signal_focus_out_event().connect([this](GdkEventFocus *event) { hide_tooltips(); + if(clickable_tag_applied) { + get_buffer()->remove_tag(clickable_tag, get_buffer()->begin(), get_buffer()->end()); + clickable_tag_applied = false; + } return false; }); @@ -883,6 +931,7 @@ void Source::View::setup_format_style(bool is_generic_view) { Source::View::~View() { delayed_tooltips_connection.disconnect(); delayed_tag_similar_symbols_connection.disconnect(); + delayed_tag_clickable_connection.disconnect(); renderer_activate_connection.disconnect(); non_deleted_views.erase(this); @@ -2637,12 +2686,7 @@ bool Source::View::on_button_press_event(GdkEventButton *event) { // Go to implementation or declaration if((event->type == GDK_BUTTON_PRESS) && (event->button == 1)) { -#ifdef __APPLE__ - GdkModifierType mask = GDK_MOD2_MASK; -#else - GdkModifierType mask = GDK_CONTROL_MASK; -#endif - if(event->state & mask) { + if(event->state & primary_modifier_mask) { int x, y; window_to_buffer_coords(Gtk::TextWindowType::TEXT_WINDOW_TEXT, event->x, event->y, x, y); Gtk::TextIter iter; diff --git a/src/source.h b/src/source.h index c437343..412ce85 100644 --- a/src/source.h +++ b/src/source.h @@ -91,8 +91,16 @@ namespace Source { Tooltips diagnostic_tooltips; Tooltips type_tooltips; sigc::connection delayed_tooltips_connection; + Glib::RefPtr similar_symbol_tag; sigc::connection delayed_tag_similar_symbols_connection; + virtual void apply_similar_symbol_tag() {} + bool similar_symbol_tag_applied = false; + Glib::RefPtr clickable_tag; + sigc::connection delayed_tag_clickable_connection; + virtual void apply_clickable_tag(const Gtk::TextIter &iter) {} + bool clickable_tag_applied = false; + virtual void show_diagnostic_tooltips(const Gdk::Rectangle &rectangle) { diagnostic_tooltips.show(rectangle); } void add_diagnostic_tooltip(const Gtk::TextIter &start, const Gtk::TextIter &end, bool error, std::function &)> &&set_buffer); void clear_diagnostic_tooltips(); @@ -125,7 +133,7 @@ namespace Source { bool interactive_completion = true; private: - void setup_tooltip_and_dialog_events(); + void setup_signals(); void setup_format_style(bool is_generic_view); Gsv::DrawSpacesFlags parse_show_whitespace_characters(const std::string &text); diff --git a/src/source_base.cc b/src/source_base.cc index 5c88518..3d4d082 100644 --- a/src/source_base.cc +++ b/src/source_base.cc @@ -45,6 +45,13 @@ Source::BaseView::BaseView(const boost::filesystem::path &file_path, const Glib: } set_tab_char_and_size(tab_char, tab_size); +#ifdef __APPLE__ + primary_modifier_mask = GDK_MOD2_MASK; +#else + primary_modifier_mask = GDK_CONTROL_MASK; +#endif + + search_settings = gtk_source_search_settings_new(); gtk_source_search_settings_set_wrap_around(search_settings, true); search_context = gtk_source_search_context_new(get_source_buffer()->gobj(), search_settings); @@ -594,7 +601,7 @@ Gtk::TextIter Source::BaseView::get_tabs_end_iter() { return get_tabs_end_iter(get_buffer()->get_insert()); } -std::string Source::BaseView::get_token(Gtk::TextIter iter) { +std::pair Source::BaseView::get_token_iters(Gtk::TextIter iter) { auto start = iter; auto end = iter; @@ -608,7 +615,12 @@ std::string Source::BaseView::get_token(Gtk::TextIter iter) { break; } - return get_buffer()->get_text(start, end); + return {start, end}; +} + +std::string Source::BaseView::get_token(const Gtk::TextIter &iter) { + auto range = get_token_iters(iter); + return get_buffer()->get_text(range.first, range.second); } void Source::BaseView::cleanup_whitespace_characters() { diff --git a/src/source_base.h b/src/source_base.h index 5067783..63cec20 100644 --- a/src/source_base.h +++ b/src/source_base.h @@ -90,6 +90,9 @@ namespace Source { std::string tab; std::pair find_tab_char_and_size(); + /// Apple key for MacOS, and control key otherwise + GdkModifierType primary_modifier_mask; + /// Move iter to line start. Depending on iter position, before or after indentation. /// Works with wrapped lines. Gtk::TextIter get_smart_home_iter(const Gtk::TextIter &iter); @@ -110,7 +113,8 @@ namespace Source { Gtk::TextIter get_tabs_end_iter(int line_nr); Gtk::TextIter get_tabs_end_iter(); - std::string get_token(Gtk::TextIter iter); + std::pair get_token_iters(Gtk::TextIter iter); + std::string get_token(const Gtk::TextIter &iter); void cleanup_whitespace_characters(); void cleanup_whitespace_characters(const Gtk::TextIter &iter); diff --git a/src/source_clang.cc b/src/source_clang.cc index a32e993..59daabc 100644 --- a/src/source_clang.cc +++ b/src/source_clang.cc @@ -17,6 +17,8 @@ clangmm::Index Source::ClangViewParse::clang_index(0, 0); +const std::regex include_regex(R"(^[ \t]*#[ \t]*include[ \t]*[<"]([^<>"]+)[>"].*$)"); + Source::ClangViewParse::ClangViewParse(const boost::filesystem::path &file_path, const Glib::RefPtr &language) : BaseView(file_path, language), Source::View(file_path, language) { Usages::Clang::erase_cache(file_path); @@ -828,13 +830,6 @@ const std::unordered_map &Source::ClangViewAutocomplet Source::ClangViewRefactor::ClangViewRefactor(const boost::filesystem::path &file_path, const Glib::RefPtr &language) : BaseView(file_path, language), Source::ClangViewParse(file_path, language) { - get_buffer()->signal_changed().connect([this]() { - if(last_tagged_identifier) { - get_buffer()->remove_tag(similar_symbol_tag, get_buffer()->begin(), get_buffer()->end()); - last_tagged_identifier = Identifier(); - } - }); - get_token_spelling = [this]() { if(!parsed) { Info::get().print("Buffer is parsing"); @@ -969,17 +964,6 @@ Source::ClangViewRefactor::ClangViewRefactor(const boost::filesystem::path &file } }; - get_buffer()->signal_mark_set().connect([this](const Gtk::TextBuffer::iterator &iterator, const Glib::RefPtr &mark) { - if(mark->get_name() == "insert") { - delayed_tag_similar_symbols_connection.disconnect(); - delayed_tag_similar_symbols_connection = Glib::signal_timeout().connect([this]() { - auto identifier = get_identifier(); - tag_similar_identifiers(identifier); - return false; - }, 100); - } - }); - auto declaration_location = [this]() { auto identifier = get_identifier(); if(identifier) { @@ -989,7 +973,6 @@ Source::ClangViewRefactor::ClangViewRefactor(const boost::filesystem::path &file } else { // If cursor is at an include line, return offset to included file - const static std::regex include_regex(R"(^[ \t]*#[ \t]*include[ \t]*[<"]([^<>"]+)[>"].*$)"); std::smatch sm; auto line = get_line(); if(std::regex_match(line, sm, include_regex)) { @@ -1721,26 +1704,51 @@ void Source::ClangViewRefactor::wait_parsing() { } } -void Source::ClangViewRefactor::tag_similar_identifiers(const Identifier &identifier) { - if(parsed) { - if(identifier && last_tagged_identifier != identifier) { - get_buffer()->remove_tag(similar_symbol_tag, get_buffer()->begin(), get_buffer()->end()); - auto offsets = clang_tokens->get_similar_token_offsets(identifier.kind, identifier.spelling, identifier.cursor.get_all_usr_extended()); - for(auto &offset : offsets) { - auto start_iter = get_buffer()->get_iter_at_line_index(offset.first.line - 1, offset.first.index - 1); - auto end_iter = get_buffer()->get_iter_at_line_index(offset.second.line - 1, offset.second.index - 1); - get_buffer()->apply_tag(similar_symbol_tag, start_iter, end_iter); +void Source::ClangViewRefactor::apply_similar_symbol_tag() { + get_buffer()->remove_tag(similar_symbol_tag, get_buffer()->begin(), get_buffer()->end()); + auto identifier = get_identifier(); + if(identifier) { + auto offsets = clang_tokens->get_similar_token_offsets(identifier.kind, identifier.spelling, identifier.cursor.get_all_usr_extended()); + for(auto &offset : offsets) { + auto start_iter = get_buffer()->get_iter_at_line_index(offset.first.line - 1, offset.first.index - 1); + auto end_iter = get_buffer()->get_iter_at_line_index(offset.second.line - 1, offset.second.index - 1); + get_buffer()->apply_tag(similar_symbol_tag, start_iter, end_iter); + } + } +} + +void Source::ClangViewRefactor::apply_clickable_tag(const Gtk::TextIter &iter) { + if(!parsed) + return; + auto line = static_cast(iter.get_line()); + auto index = static_cast(iter.get_line_index()); + + for(size_t c = clang_tokens->size() - 1; c != static_cast(-1); --c) { + auto &token = (*clang_tokens)[c]; + if(token.is_identifier()) { + auto &token_offsets = clang_tokens_offsets[c]; + if(line == token_offsets.first.line - 1 && index >= token_offsets.first.index - 1 && index <= token_offsets.second.index - 1) { + auto referenced = token.get_cursor().get_referenced(); + if(referenced) { + auto start = get_buffer()->get_iter_at_line_index(token_offsets.first.line - 1, token_offsets.first.index - 1); + auto end = get_buffer()->get_iter_at_line_index(token_offsets.second.line - 1, token_offsets.second.index - 1); + get_buffer()->apply_tag(clickable_tag, start, end); + return; + } + break; } - last_tagged_identifier = identifier; } } - if(!identifier && last_tagged_identifier) { - get_buffer()->remove_tag(similar_symbol_tag, get_buffer()->begin(), get_buffer()->end()); - last_tagged_identifier = Identifier(); + std::smatch sm; + auto line_at_iter = this->get_line(iter); + if(std::regex_match(line_at_iter, sm, include_regex)) { + auto start = get_buffer()->get_iter_at_line(line); + auto end = start; + end.forward_to_line_end(); + get_buffer()->apply_tag(clickable_tag, start, end); } } - Source::ClangView::ClangView(const boost::filesystem::path &file_path, const Glib::RefPtr &language) : BaseView(file_path, language), ClangViewParse(file_path, language), ClangViewAutocomplete(file_path, language), ClangViewRefactor(file_path, language) { if(language) { diff --git a/src/source_clang.h b/src/source_clang.h index 8a8ea6d..ea8d16f 100644 --- a/src/source_clang.h +++ b/src/source_clang.h @@ -93,12 +93,13 @@ namespace Source { public: ClangViewRefactor(const boost::filesystem::path &file_path, const Glib::RefPtr &language); + protected: + void apply_similar_symbol_tag() override; + void apply_clickable_tag(const Gtk::TextIter &iter) override; + private: Identifier get_identifier(); void wait_parsing(); - - void tag_similar_identifiers(const Identifier &identifier); - Identifier last_tagged_identifier; }; class ClangView : public ClangViewAutocomplete, public ClangViewRefactor { diff --git a/src/source_language_protocol.cc b/src/source_language_protocol.cc index bf6b5b8..e22b160 100644 --- a/src/source_language_protocol.cc +++ b/src/source_language_protocol.cc @@ -93,7 +93,7 @@ LanguageProtocol::Capabilities LanguageProtocol::Client::initialize(Source::Lang if(!error) { auto capabilities_pt = result.find("capabilities"); if(capabilities_pt != result.not_found()) { - capabilities.text_document_sync = static_cast(capabilities_pt->second.get("textDocumentSync", 0)); + capabilities.text_document_sync = static_cast(capabilities_pt->second.get("textDocumentSync", 0)); capabilities.hover = capabilities_pt->second.get("hoverProvider", false); capabilities.completion = capabilities_pt->second.find("completionProvider") != capabilities_pt->second.not_found() ? true : false; capabilities.definition = capabilities_pt->second.get("definitionProvider", false); @@ -340,20 +340,6 @@ Source::LanguageProtocolView::LanguageProtocolView(const boost::filesystem::path initialize(true); - get_buffer()->signal_changed().connect([this] { - get_buffer()->remove_tag(similar_symbol_tag, get_buffer()->begin(), get_buffer()->end()); - }); - - get_buffer()->signal_mark_set().connect([this](const Gtk::TextBuffer::iterator &iterator, const Glib::RefPtr &mark) { - if(mark->get_name() == "insert") { - delayed_tag_similar_symbols_connection.disconnect(); - delayed_tag_similar_symbols_connection = Glib::signal_timeout().connect([this]() { - tag_similar_symbols(); - return false; - }, 200); - } - }); - get_buffer()->signal_insert().connect([this](const Gtk::TextBuffer::iterator &start, const Glib::ustring &text_, int bytes) { std::string content_changes; if(capabilities.text_document_sync == LanguageProtocol::Capabilities::TextDocumentSync::NONE) @@ -514,8 +500,8 @@ void Source::LanguageProtocolView::setup_navigation_and_refactoring() { // If entire buffer is replaced: if(text_edits.size() == 1 && text_edits[0].range.start.line == 0 && text_edits[0].range.start.character == 0 && - (text_edits[0].range.end.line > static_cast(end_iter.get_line()) || - (text_edits[0].range.end.line == static_cast(end_iter.get_line()) && text_edits[0].range.end.character >= static_cast(end_iter.get_line_offset())))) { + (text_edits[0].range.end.line > end_iter.get_line() || + (text_edits[0].range.end.line == end_iter.get_line() && text_edits[0].range.end.character >= end_iter.get_line_offset()))) { replace_text(text_edits[0].new_text); } else { @@ -574,20 +560,20 @@ void Source::LanguageProtocolView::setup_navigation_and_refactoring() { }); result_processed.get_future().get(); - auto embolden_token = [](std::string &line_, unsigned token_start_pos, unsigned token_end_pos) { + auto embolden_token = [](std::string &line_, int token_start_pos, int token_end_pos) { Glib::ustring line = line_; - if(token_start_pos > line.size() || token_end_pos > line.size()) + if(static_cast(token_start_pos) > line.size() || static_cast(token_end_pos) > line.size()) return; //markup token as bold size_t pos = 0; while((pos = line.find('&', pos)) != Glib::ustring::npos) { size_t pos2 = line.find(';', pos + 2); - if(token_start_pos > pos) { + if(static_cast(token_start_pos) > pos) { token_start_pos += pos2 - pos; token_end_pos += pos2 - pos; } - else if(token_end_pos > pos) + else if(static_cast(token_end_pos) > pos) token_end_pos += pos2 - pos; else break; @@ -620,7 +606,7 @@ void Source::LanguageProtocolView::setup_navigation_and_refactoring() { } } if(view_it != views.end()) { - if(location.range.start.line < static_cast((*view_it)->get_buffer()->get_line_count())) { + if(location.range.start.line < (*view_it)->get_buffer()->get_line_count()) { auto start = (*view_it)->get_buffer()->get_iter_at_line(location.range.start.line); auto end = start; end.forward_to_line_end(); @@ -649,7 +635,7 @@ void Source::LanguageProtocolView::setup_navigation_and_refactoring() { } } - if(location.range.start.line < it->second.size()) { + if(static_cast(location.range.start.line) < it->second.size()) { usage.second = Glib::Markup::escape_text(it->second[location.range.start.line]); embolden_token(usage.second, location.range.start.character, location.range.end.character); } @@ -778,8 +764,8 @@ void Source::LanguageProtocolView::setup_navigation_and_refactoring() { // If entire buffer is replaced if(change.text_edits.size() == 1 && change.text_edits[0].range.start.line == 0 && change.text_edits[0].range.start.character == 0 && - (change.text_edits[0].range.end.line > static_cast(end_iter.get_line()) || - (change.text_edits[0].range.end.line == static_cast(end_iter.get_line()) && change.text_edits[0].range.end.character >= static_cast(end_iter.get_line_offset())))) + (change.text_edits[0].range.end.line > end_iter.get_line() || + (change.text_edits[0].range.end.line == end_iter.get_line() && change.text_edits[0].range.end.character >= end_iter.get_line_offset()))) replace_text(change.text_edits[0].new_text); else { for(auto edit_it = change.text_edits.rbegin(); edit_it != change.text_edits.rend(); ++edit_it) { @@ -812,10 +798,10 @@ void Source::LanguageProtocolView::setup_navigation_and_refactoring() { for(auto edit_it = change.text_edits.rbegin(); edit_it != change.text_edits.rend(); ++edit_it) { auto start_line = edit_it->range.start.line; auto end_line = edit_it->range.end.line; - if(start_line < lines_start_pos.size()) { + if(static_cast(start_line) < lines_start_pos.size()) { auto start = lines_start_pos[start_line] + edit_it->range.start.character; - unsigned end; - if(end_line >= lines_start_pos.size()) + size_t end; + if(static_cast(end_line) >= lines_start_pos.size()) end = buffer.size(); else end = lines_start_pos[end_line] + edit_it->range.end.character; @@ -1037,7 +1023,7 @@ void Source::LanguageProtocolView::show_type_tooltips(const Gdk::Rectangle &rect }); } -void Source::LanguageProtocolView::tag_similar_symbols() { +void Source::LanguageProtocolView::apply_similar_symbol_tag() { if(!capabilities.document_highlight && !capabilities.references) return; @@ -1063,7 +1049,7 @@ void Source::LanguageProtocolView::tag_similar_symbols() { } } dispatcher.post([this, ranges = std::move(ranges), current_request] { - if(current_request != request_count) + if(current_request != request_count || !similar_symbol_tag_applied) return; get_buffer()->remove_tag(similar_symbol_tag, get_buffer()->begin(), get_buffer()->end()); for(auto &range : ranges) { @@ -1076,6 +1062,25 @@ void Source::LanguageProtocolView::tag_similar_symbols() { }); } +void Source::LanguageProtocolView::apply_clickable_tag(const Gtk::TextIter &iter) { + static int request_count = 0; + request_count++; + auto current_request = request_count; + auto line = iter.get_line(); + auto offset = iter.get_line_offset(); + client->write_request(this, "textDocument/definition", R"("textDocument":{"uri":"file://)" + file_path.string() + R"("}, "position": {"line": )" + std::to_string(line) + ", \"character\": " + std::to_string(offset) + "}", [this, current_request, line, offset](const boost::property_tree::ptree &result, bool error) { + if(!error && !result.empty()) { + dispatcher.post([this, current_request, line, offset] { + if(current_request != request_count || !clickable_tag_applied) + return; + get_buffer()->remove_tag(clickable_tag, get_buffer()->begin(), get_buffer()->end()); + auto range = get_token_iters(get_iter_at_line_offset(line, offset)); + get_buffer()->apply_tag(clickable_tag, range.first, range.second); + }); + } + }); +} + Source::Offset Source::LanguageProtocolView::get_declaration(const Gtk::TextIter &iter) { auto offset = std::make_shared(); std::promise result_processed; @@ -1229,7 +1234,7 @@ void Source::LanguageProtocolView::setup_autocomplete() { } else { insert = label; - auto kind = it->second.get("kind", 0); + auto kind = it->second.get("kind", 0); if(kind >= 2 && kind <= 3) { bool found_bracket = false; for(auto &chr : insert) { diff --git a/src/source_language_protocol.h b/src/source_language_protocol.h index 61615cf..a4f1462 100644 --- a/src/source_language_protocol.h +++ b/src/source_language_protocol.h @@ -16,10 +16,10 @@ namespace Source { namespace LanguageProtocol { class Offset { public: - Offset(const boost::property_tree::ptree &pt) : line(pt.get("line")), - character(pt.get("character")) {} - unsigned line; - unsigned character; + Offset(const boost::property_tree::ptree &pt) : line(pt.get("line")), + character(pt.get("character")) {} + int line; + int character; }; class Range { @@ -56,14 +56,14 @@ namespace LanguageProtocol { Diagnostic(const boost::property_tree::ptree &pt) : message(pt.get("message")), range(pt.get_child("range")), - severity(pt.get("severity", 0)) { + severity(pt.get("severity", 0)) { auto related_information_it = pt.get_child("relatedInformation", boost::property_tree::ptree()); for(auto it = related_information_it.begin(); it != related_information_it.end(); ++it) related_informations.emplace_back(it->second); } std::string message; Range range; - unsigned severity; + int severity; std::vector related_informations; }; @@ -152,6 +152,8 @@ namespace Source { protected: void show_type_tooltips(const Gdk::Rectangle &rectangle) override; + void apply_similar_symbol_tag() override; + void apply_clickable_tag(const Gtk::TextIter &iter) override; private: std::string language_id;