diff --git a/src/dialogs.cc b/src/dialogs.cc index 8f66ab0..afcd1e0 100644 --- a/src/dialogs.cc +++ b/src/dialogs.cc @@ -42,9 +42,11 @@ std::string Dialog::gtk_dialog(const std::string &title, dialog.set_transient_for(*application->window); auto current_path=application->window->notebook.get_current_folder(); + boost::system::error_code ec; if(current_path.empty()) - current_path=boost::filesystem::current_path(); - gtk_file_chooser_set_current_folder((GtkFileChooser*)dialog.gobj(), current_path.string().c_str()); + current_path=boost::filesystem::current_path(ec); + if(!ec) + gtk_file_chooser_set_current_folder((GtkFileChooser*)dialog.gobj(), current_path.string().c_str()); if (!file_name.empty()) gtk_file_chooser_set_filename((GtkFileChooser*)dialog.gobj(), file_name.c_str()); diff --git a/src/dialogs_win.cc b/src/dialogs_win.cc index 377bf16..72d1869 100644 --- a/src/dialogs_win.cc +++ b/src/dialogs_win.cc @@ -99,8 +99,11 @@ private: auto application=Glib::RefPtr::cast_static(gio_application); auto current_path=application->window->notebook.get_current_folder(); + boost::system::error_code ec; if(current_path.empty()) - current_path=boost::filesystem::current_path(); + current_path=boost::filesystem::current_path(ec); + if(ec) + return false; std::wstring path=current_path.native(); size_t pos=0; diff --git a/src/directories.cc b/src/directories.cc index b643579..9aa8421 100644 --- a/src/directories.cc +++ b/src/directories.cc @@ -90,19 +90,16 @@ Directories::Directories() : stop_update_thread(false) { update_mutex.lock(); if(update_paths.size()==0) { for(auto it=last_write_times.begin();it!=last_write_times.end();) { - try { - if(boost::filesystem::exists(it->first)) { //Added for older boost versions (no exception thrown) - if(it->second.secondfirst)) { - update_paths.emplace_back(it->first); - } - it++; + boost::system::error_code ec; + auto last_write_time=boost::filesystem::last_write_time(it->first, ec); + if(!ec) { + if(it->second.secondfirst); } - else - it=last_write_times.erase(it); + it++; } - catch(const std::exception &e) { + else it=last_write_times.erase(it); - } } if(update_paths.size()>0) update_dispatcher(); @@ -198,7 +195,11 @@ void Directories::select(const boost::filesystem::path &path) { } void Directories::add_path(const boost::filesystem::path& dir_path, const Gtk::TreeModel::Row &parent) { - last_write_times[dir_path.string()]={parent, boost::filesystem::last_write_time(dir_path)}; + boost::system::error_code ec; + auto last_write_time=boost::filesystem::last_write_time(dir_path, ec); + if(ec) + return; + last_write_times[dir_path.string()]={parent, last_write_time}; std::unique_ptr children; //Gtk::TreeNodeChildren is missing default constructor... if(parent) children=std::unique_ptr(new Gtk::TreeNodeChildren(parent.children())); diff --git a/src/selectiondialog.cc b/src/selectiondialog.cc index 012ecb8..ba1daaa 100644 --- a/src/selectiondialog.cc +++ b/src/selectiondialog.cc @@ -15,8 +15,36 @@ namespace sigc { #endif } -SelectionDialogBase::SelectionDialogBase(Gtk::TextView& text_view, Glib::RefPtr start_mark, bool show_search_entry): text_view(text_view), -start_mark(start_mark), show_search_entry(show_search_entry), list_view_text(1, false, Gtk::SelectionMode::SELECTION_BROWSE) { +ListViewText::ListViewText(bool use_markup) : Gtk::TreeView(), use_markup(use_markup) { + list_store = Gtk::ListStore::create(column_record); + set_model(list_store); + append_column("", cell_renderer); + if(use_markup) + get_column(0)->add_attribute(cell_renderer.property_markup(), column_record.text); + else + get_column(0)->add_attribute(cell_renderer.property_text(), column_record.text); + + get_selection()->set_mode(Gtk::SelectionMode::SELECTION_BROWSE); + set_enable_search(true); + set_headers_visible(false); + set_hscroll_policy(Gtk::ScrollablePolicy::SCROLL_NATURAL); + set_activate_on_single_click(true); + set_hover_selection(false); + set_rules_hint(true); +} + +void ListViewText::ListViewText::append(const std::string& value) { + auto new_row=list_store->append(); + new_row->set_value(column_record.text, value); +} + +void ListViewText::ListViewText::hide() { + Gtk::TreeView::hide(); + list_store->clear(); +} + +SelectionDialogBase::SelectionDialogBase(Gtk::TextView& text_view, Glib::RefPtr start_mark, bool show_search_entry, bool use_markup): text_view(text_view), +list_view_text(use_markup), start_mark(start_mark), show_search_entry(show_search_entry) { if(!show_search_entry) window=std::unique_ptr(new Gtk::Window(Gtk::WindowType::WINDOW_POPUP)); else @@ -27,13 +55,6 @@ start_mark(start_mark), show_search_entry(show_search_entry), list_view_text(1, window->property_decorated()=false; window->set_skip_taskbar_hint(true); scrolled_window.set_policy(Gtk::PolicyType::POLICY_AUTOMATIC, Gtk::PolicyType::POLICY_AUTOMATIC); - list_view_text.set_enable_search(true); - list_view_text.set_headers_visible(false); - list_view_text.set_hscroll_policy(Gtk::ScrollablePolicy::SCROLL_NATURAL); - list_view_text.set_activate_on_single_click(true); - list_view_text.set_hover_selection(false); - list_view_text.set_rules_hint(true); - //list_view_text.set_fixed_height_mode(true); //TODO: This is buggy on OS X, remember to post an issue on GTK+ 3 list_view_text.signal_realize().connect([this](){ resize(); @@ -89,8 +110,8 @@ void SelectionDialogBase::hide() { } void SelectionDialogBase::update_tooltips() { - if(list_view_text.get_selected().size()>0) { - auto it=list_view_text.get_selection()->get_selected(); + auto it=list_view_text.get_selection()->get_selected(); + if(it) { std::string row; it->get_value(0, row); if(row!=last_row || last_row.size()==0) { @@ -155,7 +176,7 @@ void SelectionDialogBase::resize() { } } -SelectionDialog::SelectionDialog(Gtk::TextView& text_view, Glib::RefPtr start_mark, bool show_search_entry) : SelectionDialogBase(text_view, start_mark, show_search_entry) {} +SelectionDialog::SelectionDialog(Gtk::TextView& text_view, Glib::RefPtr start_mark, bool show_search_entry, bool use_markup) : SelectionDialogBase(text_view, start_mark, show_search_entry, use_markup) {} void SelectionDialog::show() { SelectionDialogBase::show(); @@ -168,6 +189,14 @@ void SelectionDialog::show() { auto search_key_lc=*search_key; std::transform(row_lc.begin(), row_lc.end(), row_lc.begin(), ::tolower); std::transform(search_key_lc.begin(), search_key_lc.end(), search_key_lc.begin(), ::tolower); + if(list_view_text.use_markup) { + size_t pos=0; + while((pos=row_lc.find('<', pos))!=std::string::npos) { + auto pos2=row_lc.find('>', pos+1); + row_lc.erase(pos, pos2-pos+1); + } + search_key_lc=Glib::Markup::escape_text(search_key_lc); + } if(row_lc.find(search_key_lc)!=std::string::npos) return true; return false; @@ -221,8 +250,8 @@ void SelectionDialog::show() { }); auto activate=[this](){ - if(on_select && list_view_text.get_selected().size()>0) { - auto it=list_view_text.get_selection()->get_selected(); + auto it=list_view_text.get_selection()->get_selected(); + if(on_select && it) { std::string row; it->get_value(0, row); on_select(row, true); @@ -288,7 +317,7 @@ bool SelectionDialog::on_key_press(GdkEventKey* key) { return false; } -CompletionDialog::CompletionDialog(Gtk::TextView& text_view, Glib::RefPtr start_mark) : SelectionDialogBase(text_view, start_mark, false) {} +CompletionDialog::CompletionDialog(Gtk::TextView& text_view, Glib::RefPtr start_mark) : SelectionDialogBase(text_view, start_mark, false, false) {} void CompletionDialog::show() { SelectionDialogBase::show(); @@ -344,8 +373,8 @@ void CompletionDialog::show() { void CompletionDialog::select(bool hide_window) { row_in_entry=true; - if(list_view_text.get_selected().size()>0) { - auto it=list_view_text.get_selection()->get_selected(); + auto it=list_view_text.get_selection()->get_selected(); + if(it) { std::string row; it->get_value(0, row); if(on_select) diff --git a/src/selectiondialog.h b/src/selectiondialog.h index 499c86f..b13fffb 100644 --- a/src/selectiondialog.h +++ b/src/selectiondialog.h @@ -6,9 +6,28 @@ #include "tooltips.h" #include +class ListViewText : public Gtk::TreeView { + class ColumnRecord : public Gtk::TreeModel::ColumnRecord { + public: + ColumnRecord() { + add(text); + } + Gtk::TreeModelColumn text; + }; +public: + bool use_markup; + ListViewText(bool use_markup); + void append(const std::string& value); + void hide(); +private: + Glib::RefPtr list_store; + ColumnRecord column_record; + Gtk::CellRendererText cell_renderer; +}; + class SelectionDialogBase { public: - SelectionDialogBase(Gtk::TextView& text_view, Glib::RefPtr start_mark, bool show_search_entry); + SelectionDialogBase(Gtk::TextView& text_view, Glib::RefPtr start_mark, bool show_search_entry, bool use_markup); ~SelectionDialogBase(); virtual void add_row(const std::string& row, const std::string& tooltip=""); virtual void show(); @@ -25,7 +44,7 @@ protected: std::unique_ptr window; Gtk::ScrolledWindow scrolled_window; - Gtk::ListViewText list_view_text; + ListViewText list_view_text; Gtk::Entry search_entry; bool show_search_entry; std::unique_ptr tooltips; @@ -37,7 +56,7 @@ private: class SelectionDialog : public SelectionDialogBase { public: - SelectionDialog(Gtk::TextView& text_view, Glib::RefPtr start_mark, bool show_search_entry=true); + SelectionDialog(Gtk::TextView& text_view, Glib::RefPtr start_mark, bool show_search_entry=true, bool use_markup=false); bool on_key_press(GdkEventKey* key); void show(); }; diff --git a/src/source.cc b/src/source.cc index 2688854..c31c828 100644 --- a/src/source.cc +++ b/src/source.cc @@ -371,8 +371,10 @@ void Source::View::configure() { note_tag->property_foreground()=style->property_foreground(); } - if(Singleton::config->source.spellcheck_language.size()>0) + if(Singleton::config->source.spellcheck_language.size()>0) { aspell_config_replace(spellcheck_config, "lang", Singleton::config->source.spellcheck_language.c_str()); + aspell_config_replace(spellcheck_config, "encoding", "utf-8"); + } spellcheck_possible_err=new_aspell_speller(spellcheck_config); if(spellcheck_checker!=NULL) delete_aspell_speller(spellcheck_checker); @@ -533,10 +535,13 @@ void Source::View::replace_all(const std::string &replacement) { void Source::View::paste() { std::string text=Gtk::Clipboard::get()->wait_for_text(); - //remove carriage returns (which leads to crash) - for(auto it=text.begin();it!=text.end();it++) { - if(*it=='\r') { - it=text.erase(it); + //Replace carriage returns (which leads to crash) with newlines + for(size_t c=0;cget_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')) + 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(); - usages.emplace_back(Offset(offset.first.line-1, offset.first.index-1, this->file_path), get_buffer()->get_text(start_iter, end_iter)); + 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; + } + 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, this->file_path), line); } } @@ -1083,14 +1106,43 @@ Source::ClangViewAutocomplete(file_path, project_path, language) { if(!visible_rect.intersects(iter_rect)) { get_iter_at_location(iter, 0, visible_rect.get_y()+visible_rect.get_height()/3); } - selection_dialog=std::unique_ptr(new SelectionDialog(*this, get_buffer()->create_mark(iter))); + selection_dialog=std::unique_ptr(new SelectionDialog(*this, get_buffer()->create_mark(iter), true, true)); auto rows=std::make_shared >(); auto methods=clang_tokens->get_cxx_methods(); if(methods.size()==0) return; for(auto &method: methods) { - (*rows)[method.first]=method.second; - selection_dialog->add_row(method.first); + std::string row=std::to_string(method.second.line)+": "+Glib::Markup::escape_text(method.first); + //Add bold method token + size_t token_end_pos=row.find('('); + if(token_end_pos==0 || token_end_pos==std::string::npos) + continue; + if(token_end_pos>8 && row.substr(token_end_pos-4, 4)==">") { + token_end_pos-=8; + size_t angle_bracket_count=1; + do { + if(row.substr(token_end_pos-4, 4)==">") { + angle_bracket_count++; + token_end_pos-=4; + } + else if(row.substr(token_end_pos-4, 4)=="<") { + angle_bracket_count--; + token_end_pos-=4; + } + else + token_end_pos--; + } while(angle_bracket_count>0 && token_end_pos>4); + } + auto pos=token_end_pos; + do { + pos--; + } while(((row[pos]>='a' && row[pos]<='z') || + (row[pos]>='A' && row[pos]<='Z') || + (row[pos]>='0' && row[pos]<='9') || row[pos]=='_' || row[pos]=='~') && pos>0); + row.insert(token_end_pos, ""); + row.insert(pos+1, ""); + (*rows)[row]=method.second; + selection_dialog->add_row(row); } selection_dialog->on_select=[this, rows](const std::string& selected, bool hide_window) { auto offset=rows->at(selected); diff --git a/src/window.cc b/src/window.cc index c53443c..6ba18f4 100644 --- a/src/window.cc +++ b/src/window.cc @@ -172,7 +172,9 @@ void Window::set_menu_actions() { auto time_now=std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); boost::filesystem::path path = Dialog::new_folder(); if(path!="" && boost::filesystem::exists(path)) { - if(boost::filesystem::last_write_time(path)>=time_now) { + boost::system::error_code ec; + auto last_write_time=boost::filesystem::last_write_time(path, ec); + if(!ec && last_write_time>=time_now) { if(Singleton::directories->current_path!="") Singleton::directories->update(); Singleton::terminal->print("New folder "+path.string()+" created.\n"); @@ -425,7 +427,7 @@ void Window::set_menu_actions() { if(!visible_rect.intersects(iter_rect)) { current_view->get_iter_at_location(iter, 0, visible_rect.get_y()+visible_rect.get_height()/3); } - current_view->selection_dialog=std::unique_ptr(new SelectionDialog(*current_view, current_view->get_buffer()->create_mark(iter))); + current_view->selection_dialog=std::unique_ptr(new SelectionDialog(*current_view, current_view->get_buffer()->create_mark(iter), true, true)); auto rows=std::make_shared >(); //First add usages in current file @@ -464,10 +466,7 @@ void Window::set_menu_actions() { notebook.open(declaration_file); auto view=notebook.get_current_view(); view->get_buffer()->place_cursor(view->get_buffer()->get_iter_at_line_index(offset.line, offset.index)); - while(g_main_context_pending(NULL)) - g_main_context_iteration(NULL, false); - if(notebook.get_current_page()!=-1) - view->scroll_to(view->get_buffer()->get_insert(), 0.0, 1.0, 0.5); + view->scroll_to(view->get_buffer()->get_insert(), 0.0, 1.0, 0.5); view->delayed_tooltips_connection.disconnect(); }; current_view->selection_dialog->show(); @@ -877,7 +876,7 @@ void Window::rename_token_entry() { 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) { + if(*token) { entry_box.labels.emplace_back(); auto label_it=entry_box.labels.begin(); label_it->update=[label_it](int state, const std::string& message){