diff --git a/src/info.cc b/src/info.cc index 5b797c1..043df5f 100644 --- a/src/info.cc +++ b/src/info.cc @@ -38,9 +38,6 @@ Info::Info() { } void Info::print(const std::string &text) { - if(!enabled) - return; - timeout_connection.disconnect(); //Timeout based on https://en.wikipedia.org/wiki/Words_per_minute //(average_words_per_minute*average_letters_per_word)/60 => (228*4.5)/60 = 17.1 diff --git a/src/info.h b/src/info.h index c89ced1..8bb78c7 100644 --- a/src/info.h +++ b/src/info.h @@ -12,7 +12,6 @@ public: } void print(const std::string &text); - bool enabled=true; private: Gtk::Label label; diff --git a/src/notebook.h b/src/notebook.h index db38ee6..22c9243 100644 --- a/src/notebook.h +++ b/src/notebook.h @@ -37,11 +37,12 @@ public: void configure(int view_nr); boost::filesystem::path get_current_folder(); + std::vector source_views; //Is NOT freed in destructor, this is intended for quick program exit. + Gtk::Label info; Gtk::Label status; private: bool save_modified_dialog(int page); - std::vector source_views; //Is NOT freed in destructor, this is intended for quick program exit. std::vector > source_maps; std::vector > scrolled_windows; std::vector > hboxes; diff --git a/src/source.cc b/src/source.cc index f3c0f15..206405f 100644 --- a/src/source.cc +++ b/src/source.cc @@ -395,7 +395,7 @@ Gsv::DrawSpacesFlags Source::View::parse_show_whitespace_characters(const std::s static_cast(std::accumulate(out.begin(), out.end(), 0)); } -bool Source::View::save(const std::vector views) { +bool Source::View::save(const std::vector &views) { if(file_path.empty() || !get_buffer()->get_modified()) return false; //Remove trailing whitespace characters on save, and add trailing newline if missing @@ -1617,7 +1617,7 @@ bool Source::View::on_focus_in_event(GdkEventFocus* focus_event){ boost::system::error_code ec; auto last_write_time=boost::filesystem::last_write_time(file_path, ec); if(!ec && last_write_time>last_read_time) - Info::get().print(file_path.filename().string() + " was changed outside juCi++, continue with caution."); + Info::get().print("Caution: " + file_path.filename().string() + " was altered outside of juCi++"); return Gsv::View::on_focus_in_event(focus_event); }; diff --git a/src/source.h b/src/source.h index fbd17a7..925280a 100644 --- a/src/source.h +++ b/src/source.h @@ -26,27 +26,11 @@ namespace Source { Glib::RefPtr guess_language(const boost::filesystem::path &file_path); - class Token { - public: - Token(): type(-1) {} - Token(Glib::RefPtr language, int type, const std::string &spelling, const std::string &usr): - language(language), type(type), spelling(spelling), usr(usr) {} - operator bool() const {return (type>=0 && spelling.size()>0 && usr.size()>0);} - bool operator==(const Token &o) const {return (type==o.type && - spelling==o.spelling && - usr==o.usr);} - bool operator!=(const Token &o) const {return !(*this==o);} - - Glib::RefPtr language; - int type; - std::string spelling; - std::string usr; - }; - class Offset { public: Offset() {} Offset(unsigned line, unsigned index, const boost::filesystem::path &file_path=""): line(line), index(index), file_path(file_path) {} + operator bool() { return !file_path.empty(); } bool operator==(const Offset &o) {return (line==o.line && index==o.index);} unsigned line; @@ -72,7 +56,7 @@ namespace Source { View(const boost::filesystem::path &file_path, Glib::RefPtr language); ~View(); - virtual bool save(const std::vector views); + virtual bool save(const std::vector &views); virtual void configure(); void search_highlight(const std::string &text, bool case_sensitive, bool regex); @@ -90,12 +74,12 @@ namespace Source { std::function auto_indent; std::function get_declaration_location; - std::function get_implementation_location; - std::function >(const Token &token)> get_usages; + std::function &views)> get_implementation_location; + std::function >(const std::vector &views)> get_usages; std::function goto_method; - std::function get_token; std::function()> get_token_data; - std::function rename_similar_tokens; + std::function get_token_spelling; + std::function >(const std::vector &views, const std::string &text)> rename_similar_tokens; std::function goto_next_diagnostic; std::function apply_fix_its; diff --git a/src/source_clang.cc b/src/source_clang.cc index 1d3b150..f087925 100644 --- a/src/source_clang.cc +++ b/src/source_clang.cc @@ -43,7 +43,7 @@ Source::View(file_path, language) { }); } -bool Source::ClangViewParse::save(const std::vector views) { +bool Source::ClangViewParse::save(const std::vector &views) { if(!Source::View::save(views)) return false; @@ -191,7 +191,7 @@ void Source::ClangViewParse::soft_reparse() { std::vector Source::ClangViewParse::get_compilation_commands() { auto build=Project::Build::create(file_path); if(build->project_path.empty()) - Info::get().print("Could not find a supported build system"); + Info::get().print(file_path.filename().string()+": could not find a supported build system"); auto default_build_path=build->get_default_path(); build->update_default(); clang::CompilationDatabase db(default_build_path.string()); @@ -416,14 +416,14 @@ void Source::ClangViewParse::show_type_tooltips(const Gdk::Rectangle &rectangle) return; } if(found_token && iter.forward_char()) { - auto tokens=clang_tu->get_tokens(iter.get_line()+1, iter.get_line_index()+1, + auto tokens=clang_tu->get_tokens(iter.get_line()+1, iter.get_line_index()+1, iter.get_line()+1, iter.get_line_index()+1); type_tooltips.clear(); for(auto &token: *tokens) { auto cursor=token.get_cursor(); if(token.get_kind()==clang::Token_Identifier && cursor.has_type()) { - if(static_cast(token.get_cursor().get_kind())==103) //These cursors are buggy + if(token.get_cursor().get_kind()==clang::CursorKind::CallExpr) //These cursors are buggy continue; 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); @@ -876,60 +876,59 @@ Source::ClangViewAutocomplete(file_path, language) { } }); - get_token=[this]() -> Token { + get_token_spelling=[this]() { if(!parsed) { Info::get().print("Buffer is parsing"); - return Token(); + return std::string(); } - auto iter=get_buffer()->get_insert()->get_iter(); - auto line=static_cast(iter.get_line()); - auto index=static_cast(iter.get_line_index()); - for(auto &token: *clang_tokens) { - auto cursor=token.get_cursor(); - if(token.get_kind()==clang::Token_Identifier && cursor.has_type()) { - if(line==token.offsets.first.line-1 && index>=token.offsets.first.index-1 && index <=token.offsets.second.index-1) { - if(static_cast(token.get_cursor().get_kind())==103) //These cursors are buggy - continue; - auto referenced=cursor.get_referenced(); - if(referenced) - return Token(this->language, static_cast(referenced.get_kind()), token.get_spelling(), referenced.get_usr()); - } - } - } - return Token(); + return get_token().spelling; }; - rename_similar_tokens=[this](const Token &token, const std::string &text) { - size_t number=0; - if(parsed && token.language && - (token.language->get_id()=="chdr" || token.language->get_id()=="cpphdr" || token.language->get_id()=="c" || token.language->get_id()=="cpp" || token.language->get_id()=="objc")) { - auto offsets=clang_tokens->get_similar_token_offsets(static_cast(token.type), token.spelling, token.usr); - std::vector, Glib::RefPtr > > marks; - for(auto &offset: offsets) { - marks.emplace_back(get_buffer()->create_mark(get_buffer()->get_iter_at_line_index(offset.first.line-1, offset.first.index-1)), get_buffer()->create_mark(get_buffer()->get_iter_at_line_index(offset.second.line-1, offset.second.index-1))); - number++; - } - get_source_buffer()->begin_user_action(); - for(auto &mark: marks) { - renaming=true; - get_buffer()->erase(mark.first->get_iter(), mark.second->get_iter()); - get_buffer()->insert(mark.first->get_iter(), text); - get_buffer()->delete_mark(mark.first); - get_buffer()->delete_mark(mark.second); + rename_similar_tokens=[this](const std::vector &views, const std::string &text) { + std::vector > renamed; + if(!parsed) { + Info::get().print("Buffer is parsing"); + return renamed; + } + auto token=get_token(); + if(token) { + std::vector renamed_views; + for(auto &view: views) { + if(auto clang_view=dynamic_cast(view)) { + auto offsets=clang_view->clang_tokens->get_similar_token_offsets(token.kind, token.spelling, token.usr); + std::vector, Glib::RefPtr > > marks; + for(auto &offset: offsets) { + marks.emplace_back(clang_view->get_buffer()->create_mark(clang_view->get_buffer()->get_iter_at_line_index(offset.first.line-1, offset.first.index-1)), + clang_view->get_buffer()->create_mark(clang_view->get_buffer()->get_iter_at_line_index(offset.second.line-1, offset.second.index-1))); + } + if(!marks.empty()) { + clang_view->renaming=true; + clang_view->get_source_buffer()->begin_user_action(); + for(auto &mark: marks) { + clang_view->get_buffer()->erase(mark.first->get_iter(), mark.second->get_iter()); + clang_view->get_buffer()->insert(mark.first->get_iter(), text); + clang_view->get_buffer()->delete_mark(mark.first); + clang_view->get_buffer()->delete_mark(mark.second); + } + clang_view->get_source_buffer()->end_user_action(); + clang_view->renaming=false; + clang_view->save(views); + renamed_views.emplace_back(clang_view); + renamed.emplace_back(clang_view->file_path, marks.size()); + } + } } - get_source_buffer()->end_user_action(); - renaming=false; + for(auto &view: renamed_views) + view->soft_reparse_needed=false; } - return number; + return renamed; }; get_buffer()->signal_mark_set().connect([this](const Gtk::TextBuffer::iterator& iterator, const Glib::RefPtr& mark){ if(mark->get_name()=="insert") { delayed_tag_similar_tokens_connection.disconnect(); delayed_tag_similar_tokens_connection=Glib::signal_timeout().connect([this]() { - Info::get().enabled=false; auto token=get_token(); - Info::get().enabled=true; tag_similar_tokens(token); return false; }, 100); @@ -963,23 +962,32 @@ Source::ClangViewAutocomplete(file_path, language) { return location; }; - get_implementation_location=[this](const Token &token){ + get_implementation_location=[this](const std::vector &views){ Offset location; - if(parsed && this->language && this->language->get_id()!="chdr" && this->language->get_id()!="cpphdr") { - for(auto token_it=clang_tokens->rbegin();token_it!=clang_tokens->rend();++token_it) { - auto cursor=token_it->get_cursor(); - auto kind=cursor.get_kind(); - if((kind==clang::CursorKind::FunctionDecl || kind==clang::CursorKind::CXXMethod || - kind==clang::CursorKind::Constructor || kind==clang::CursorKind::Destructor) && - token_it->get_kind()==clang::Token_Identifier && cursor.has_type()) { - auto referenced=cursor.get_referenced(); - if(referenced && static_cast(token.type)==referenced.get_kind() && - token.spelling==token_it->get_spelling() && token.usr==referenced.get_usr()) { - location.file_path=cursor.get_source_location().get_path(); - auto clang_offset=cursor.get_source_location().get_offset(); - location.line=clang_offset.line; - location.index=clang_offset.index; - break; + if(!parsed) { + Info::get().print("Buffer is parsing"); + return location; + } + auto token=get_token(); + for(auto &view: views) { + if(auto clang_view=dynamic_cast(view)) { + if(clang_view->language && clang_view->language->get_id()!="chdr" && clang_view->language->get_id()!="cpphdr") { + for(auto token_it=clang_view->clang_tokens->rbegin();token_it!=clang_view->clang_tokens->rend();++token_it) { + auto cursor=token_it->get_cursor(); + auto kind=cursor.get_kind(); + if((kind==clang::CursorKind::FunctionDecl || kind==clang::CursorKind::CXXMethod || + kind==clang::CursorKind::Constructor || kind==clang::CursorKind::Destructor) && + token_it->get_kind()==clang::Token_Identifier && cursor.has_type()) { + auto referenced=cursor.get_referenced(); + if(referenced && token.kind==referenced.get_kind() && + token.spelling==token_it->get_spelling() && token.usr==referenced.get_usr()) { + location.file_path=cursor.get_source_location().get_path(); + auto clang_offset=cursor.get_source_location().get_offset(); + location.line=clang_offset.line; + location.index=clang_offset.index; + return location; + } + } } } } @@ -987,42 +995,54 @@ Source::ClangViewAutocomplete(file_path, language) { return location; }; - get_usages=[this](const Token &token) { + get_usages=[this](const std::vector &views) { std::vector > usages; - if(parsed && token.language && - (token.language->get_id()=="chdr" || token.language->get_id()=="cpphdr" || token.language->get_id()=="c" || token.language->get_id()=="cpp" || token.language->get_id()=="objc")) { - auto offsets=clang_tokens->get_similar_token_offsets(static_cast(token.type), token.spelling, token.usr); - for(auto &offset: offsets) { - size_t whitespaces_removed=0; - auto start_iter=get_buffer()->get_iter_at_line(offset.first.line-1); - while(!start_iter.ends_line() && (*start_iter==' ' || *start_iter=='\t')) { - start_iter.forward_char(); - whitespaces_removed++; - } - auto end_iter=start_iter; - while(!end_iter.ends_line()) - end_iter.forward_char(); - std::string line=Glib::Markup::escape_text(get_buffer()->get_text(start_iter, end_iter)); - - //markup token as bold - size_t token_start_pos=offset.first.index-1-whitespaces_removed; - size_t token_end_pos=offset.second.index-1-whitespaces_removed; - size_t pos=0; - while((pos=line.find('&', pos))!=std::string::npos) { - size_t pos2=line.find(';', pos+2); - if(token_start_pos>pos) { - token_start_pos+=pos2-pos; - token_end_pos+=pos2-pos; + if(!parsed) { + Info::get().print("Buffer is parsing"); + return usages; + } + auto token=get_token(); + std::vector views_reordered; + views_reordered.emplace_back(this); + for(auto &view: views) { + if(view!=this) + views_reordered.emplace_back(view); + } + for(auto &view: views_reordered) { + if(auto clang_view=dynamic_cast(view)) { + auto offsets=clang_view->clang_tokens->get_similar_token_offsets(token.kind, token.spelling, token.usr); + for(auto &offset: offsets) { + size_t whitespaces_removed=0; + auto start_iter=clang_view->get_buffer()->get_iter_at_line(offset.first.line-1); + while(!start_iter.ends_line() && (*start_iter==' ' || *start_iter=='\t')) { + start_iter.forward_char(); + whitespaces_removed++; } - else if(token_end_pos>pos) - token_end_pos+=pos2-pos; - else - break; - pos=pos2+1; + auto end_iter=start_iter; + while(!end_iter.ends_line()) + end_iter.forward_char(); + std::string line=Glib::Markup::escape_text(clang_view->get_buffer()->get_text(start_iter, end_iter)); + + //markup token as bold + size_t token_start_pos=offset.first.index-1-whitespaces_removed; + size_t token_end_pos=offset.second.index-1-whitespaces_removed; + size_t pos=0; + while((pos=line.find('&', pos))!=std::string::npos) { + size_t pos2=line.find(';', pos+2); + if(token_start_pos>pos) { + token_start_pos+=pos2-pos; + token_end_pos+=pos2-pos; + } + else if(token_end_pos>pos) + token_end_pos+=pos2-pos; + else + break; + pos=pos2+1; + } + line.insert(token_end_pos, ""); + line.insert(token_start_pos, ""); + usages.emplace_back(Offset(offset.first.line-1, offset.first.index-1, clang_view->file_path), line); } - line.insert(token_end_pos, ""); - line.insert(token_start_pos, ""); - usages.emplace_back(Offset(offset.first.line-1, offset.first.index-1, this->file_path), line); } } @@ -1237,6 +1257,27 @@ Source::ClangViewAutocomplete(file_path, language) { }; } +Source::ClangViewRefactor::Token Source::ClangViewRefactor::get_token() { + if(!parsed) + return Token(); + auto iter=get_buffer()->get_insert()->get_iter(); + auto line=static_cast(iter.get_line()); + auto index=static_cast(iter.get_line_index()); + for(auto &token: *clang_tokens) { + auto cursor=token.get_cursor(); + if(token.get_kind()==clang::Token_Identifier && cursor.has_type()) { + if(line==token.offsets.first.line-1 && index>=token.offsets.first.index-1 && index <=token.offsets.second.index-1) { + if(token.get_cursor().get_kind()==clang::CursorKind::CallExpr) //These cursors are buggy + continue; + auto referenced=cursor.get_referenced(); + if(referenced) + return Token(referenced.get_kind(), token.get_spelling(), referenced.get_usr()); + } + } + } + return Token(); +} + void Source::ClangViewRefactor::tag_similar_tokens(const Token &token) { if(parsed) { if(token && last_tagged_token!=token) { @@ -1246,7 +1287,7 @@ void Source::ClangViewRefactor::tag_similar_tokens(const Token &token) { get_buffer()->delete_mark(mark.second); } similar_token_marks.clear(); - auto offsets=clang_tokens->get_similar_token_offsets(static_cast(token.type), token.spelling, token.usr); + auto offsets=clang_tokens->get_similar_token_offsets(token.kind, token.spelling, token.usr); 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); diff --git a/src/source_clang.h b/src/source_clang.h index 028059a..5083453 100644 --- a/src/source_clang.h +++ b/src/source_clang.h @@ -15,7 +15,7 @@ namespace Source { protected: enum class ParseState {PROCESSING, RESTARTING, STOP}; enum class ParseProcessState {IDLE, STARTING, PREPROCESSING, PROCESSING, POSTPROCESSING}; - public: + class TokenRange { public: TokenRange(std::pair offsets, int kind): @@ -24,9 +24,10 @@ namespace Source { int kind; }; + public: ClangViewParse(const boost::filesystem::path &file_path, Glib::RefPtr language); - bool save(const std::vector views) override; + bool save(const std::vector &views) override; void configure() override; void soft_reparse() override; @@ -99,11 +100,24 @@ namespace Source { }; class ClangViewRefactor : public ClangViewAutocomplete { + class Token { + public: + Token(clang::CursorKind kind, const std::string &spelling, const std::string &usr) : kind(kind), spelling(spelling), usr(usr) {} + Token() : kind(static_cast(0)) {} + operator bool() const { return static_cast(kind)!=0; } + bool operator==(const Token &other) const { return (kind==other.kind && spelling==other.spelling && usr==other.usr); } + bool operator!=(const Token &other) const { return !(*this==other); } + clang::CursorKind kind; + std::string spelling; + std::string usr; + }; public: ClangViewRefactor(const boost::filesystem::path &file_path, Glib::RefPtr language); protected: sigc::connection delayed_tag_similar_tokens_connection; private: + Token get_token(); + std::list, Glib::RefPtr > > similar_token_marks; void tag_similar_tokens(const Token &token); Glib::RefPtr similar_tokens_tag; diff --git a/src/window.cc b/src/window.cc index 106f6d4..1e80628 100644 --- a/src/window.cc +++ b/src/window.cc @@ -436,7 +436,7 @@ void Window::set_menu_actions() { if(notebook.get_current_page()!=-1) { if(notebook.get_current_view()->get_declaration_location) { auto location=notebook.get_current_view()->get_declaration_location(); - if(!location.file_path.empty()) { + if(location) { boost::filesystem::path declaration_file; boost::system::error_code ec; declaration_file=boost::filesystem::canonical(location.file_path, ec); @@ -454,72 +454,51 @@ void Window::set_menu_actions() { }); menu.add_action("source_goto_implementation", [this]() { if(notebook.get_current_page()!=-1) { - auto current_view=notebook.get_current_view(); - if(current_view->get_token) { - auto token=current_view->get_token(); - if(token) { - for(int page=0;pageget_implementation_location) { - auto location=view->get_implementation_location(token); - if(!location.file_path.empty()) { - boost::filesystem::path implementation_path; - boost::system::error_code ec; - implementation_path=boost::filesystem::canonical(location.file_path, ec); - if(ec) - return; - notebook.open(implementation_path); - auto view=notebook.get_current_view(); - auto line=static_cast(location.line)-1; - auto index=static_cast(location.index)-1; - view->place_cursor_at_line_index(line, index); - view->scroll_to_cursor_delayed(view, true, false); - return; - } - } - } - Info::get().print("Could not find implementation"); + auto view=notebook.get_current_view(); + if(view->get_implementation_location) { + auto location=view->get_implementation_location(notebook.source_views); + if(location) { + boost::filesystem::path implementation_path; + boost::system::error_code ec; + implementation_path=boost::filesystem::canonical(location.file_path, ec); + if(ec) + return; + notebook.open(implementation_path); + auto view=notebook.get_current_view(); + auto line=static_cast(location.line)-1; + auto index=static_cast(location.index)-1; + view->place_cursor_at_line_index(line, index); + view->scroll_to_cursor_delayed(view, true, false); + return; } + Info::get().print("Could not find implementation"); } } }); + menu.add_action("source_goto_usage", [this]() { if(notebook.get_current_page()!=-1) { - auto current_view=notebook.get_current_view(); - if(current_view->get_token && current_view->get_usages) { - auto token=current_view->get_token(); - if(token) { - auto iter=current_view->get_iter_for_dialog(); - current_view->selection_dialog=std::unique_ptr(new SelectionDialog(*current_view, current_view->get_buffer()->create_mark(iter), true, true)); + auto view=notebook.get_current_view(); + if(view->get_usages) { + auto usages=view->get_usages(notebook.source_views); + if(!usages.empty()) { + auto iter=view->get_iter_for_dialog(); + view->selection_dialog=std::unique_ptr(new SelectionDialog(*view, view->get_buffer()->create_mark(iter), true, true)); auto rows=std::make_shared >(); - //First add usages in current file - auto usages=current_view->get_usages(token); for(auto &usage: usages) { - auto iter=current_view->get_buffer()->get_iter_at_line_index(usage.first.line, usage.first.index); - auto row=std::to_string(iter.get_line()+1)+':'+std::to_string(iter.get_line_offset()+1)+' '+usage.second; + std::string row; + //add file name if usage is not in current tab + if(view->file_path!=usage.first.file_path) + row=usage.first.file_path.filename().string()+":"; + row+=std::to_string(usage.first.line+1)+": "+usage.second; (*rows)[row]=usage.first; - current_view->selection_dialog->add_row(row); - } - //Then the remaining opened files - for(int page=0;pageget_usages) { - auto usages=view->get_usages(token); - for(auto &usage: usages) { - auto iter=view->get_buffer()->get_iter_at_line_index(usage.first.line, usage.first.index); - auto row=usage.first.file_path.filename().string()+":"+std::to_string(iter.get_line()+1)+':'+std::to_string(iter.get_line_offset()+1)+' '+usage.second; - (*rows)[row]=usage.first; - current_view->selection_dialog->add_row(row); - } - } - } + view->selection_dialog->add_row(row); } if(rows->size()==0) return; - current_view->selection_dialog->on_select=[this, rows](const std::string& selected, bool hide_window) { + view->selection_dialog->on_select=[this, rows](const std::string &selected, bool hide_window) { auto offset=rows->at(selected); boost::filesystem::path declaration_file; boost::system::error_code ec; @@ -532,7 +511,7 @@ void Window::set_menu_actions() { view->scroll_to(view->get_buffer()->get_insert(), 0.0, 1.0, 0.5); view->delayed_tooltips_connection.disconnect(); }; - current_view->selection_dialog->show(); + view->selection_dialog->show(); } } } @@ -1087,33 +1066,29 @@ void Window::goto_line_entry() { void Window::rename_token_entry() { EntryBox::get().clear(); if(notebook.get_current_page()!=-1) { - if(notebook.get_current_view()->get_token) { - auto token=std::make_shared(notebook.get_current_view()->get_token()); - if(*token) { + auto view=notebook.get_current_view(); + if(view->get_token_spelling && view->rename_similar_tokens) { + auto spelling=std::make_shared(view->get_token_spelling()); + if(!spelling->empty()) { EntryBox::get().labels.emplace_back(); auto label_it=EntryBox::get().labels.begin(); label_it->update=[label_it](int state, const std::string& message){ label_it->set_text("Warning: only opened and parsed tabs will have its content renamed, and modified files will be saved"); }; label_it->update(0, ""); - EntryBox::get().entries.emplace_back(token->spelling, [this, token](const std::string& content){ - if(notebook.get_current_page()!=-1 && content!=token->spelling) { - std::vector modified_pages; - for(int c=0;crename_similar_tokens) { - auto number=view->rename_similar_tokens(*token, content); - if(number>0) { - Terminal::get().print("Replaced "+std::to_string(number)+" occurrences in file "+view->file_path.string()+"\n"); - notebook.save(c); - modified_pages.emplace_back(c); - } - } - } - for(auto &page: modified_pages) - notebook.get_view(page)->soft_reparse_needed=false; - EntryBox::get().hide(); + auto iter=std::make_shared(view->get_buffer()->get_insert()->get_iter()); + EntryBox::get().entries.emplace_back(*spelling, [this, view, spelling, iter](const std::string& content){ + //TODO: gtk needs a way to check if iter is valid without dumping g_error message + //iter->get_buffer() will print such a message, but no segfault will occur + if(notebook.get_current_page()!=-1 && notebook.get_current_view()==view && + content!=*spelling && iter->get_buffer() && view->get_buffer()->get_insert()->get_iter()==*iter) { + auto renamed_pairs=view->rename_similar_tokens(notebook.source_views, content); + for(auto &renamed: renamed_pairs) + Terminal::get().print("Replaced "+std::to_string(renamed.second)+" occurrences in file "+renamed.first.string()+"\n"); } + else + Info::get().print("Operation canceled"); + EntryBox::get().hide(); }); auto entry_it=EntryBox::get().entries.begin(); entry_it->set_placeholder_text("New name");