diff --git a/src/cmake.cc b/src/cmake.cc index 2281ae5..620575f 100644 --- a/src/cmake.cc +++ b/src/cmake.cc @@ -10,33 +10,28 @@ CMake::CMake(const boost::filesystem::path &path) { for(auto &line: filesystem::read_lines(cmake_path)) { const boost::regex project_regex("^ *project *\\(.*$"); boost::smatch sm; - if(boost::regex_match(line, sm, project_regex)) { + if(boost::regex_match(line, sm, project_regex)) return true; - } } return false; }; auto search_path=path; - auto search_cmake_path=search_path; - search_cmake_path+="/CMakeLists.txt"; - if(boost::filesystem::exists(search_cmake_path)) - paths.emplace(paths.begin(), search_cmake_path); - if(find_cmake_project(search_cmake_path)) - project_path=search_path; - else { - do { - search_path=search_path.parent_path(); - search_cmake_path=search_path; - search_cmake_path+="/CMakeLists.txt"; - if(boost::filesystem::exists(search_cmake_path)) - paths.emplace(paths.begin(), search_cmake_path); - if(find_cmake_project(search_cmake_path)) { - project_path=search_path; - break; - } - } while(search_path!=search_path.root_directory()); + while(true) { + auto search_cmake_path=search_path/"CMakeLists.txt"; + if(boost::filesystem::exists(search_cmake_path)) + paths.emplace(paths.begin(), search_cmake_path); + else + break; + if(find_cmake_project(search_cmake_path)) { + project_path=search_path; + break; + } + if(search_path==search_path.root_directory()) + break; + search_path=search_path.parent_path(); } + if(!project_path.empty()) { if(boost::filesystem::exists(project_path/"CMakeLists.txt") && !boost::filesystem::exists(project_path/"compile_commands.json")) create_compile_commands(project_path); @@ -140,8 +135,8 @@ void CMake::find_variables() { end_line=file.size(); if(end_line>start_line) { auto line=file.substr(start_line, end_line-start_line); - const boost::regex set_regex("^ *set *\\( *([A-Za-z_][A-Za-z_0-9]*) +(.*)\\) *$"); boost::smatch sm; + const boost::regex set_regex("^ *set *\\( *([A-Za-z_][A-Za-z_0-9]*) +(.*)\\) *$"); if(boost::regex_match(line, sm, set_regex)) { auto data=sm[2].str(); while(data.size()>0 && data.back()==' ') @@ -149,6 +144,15 @@ void CMake::find_variables() { parse_variable_parameters(data); variables[sm[1].str()]=data; } + else { + const boost::regex project_regex("^ *project *\\( *([^ ]+).*\\) *$"); + if(boost::regex_match(line, sm, project_regex)) { + auto data=sm[1].str(); + parse_variable_parameters(data); + variables["CMAKE_PROJECT_NAME"]=data; //TODO: is this variable deprecated/non-standard? + variables["PROJECT_NAME"]=data; + } + } } pos=end_line+1; } diff --git a/src/selectiondialog.h b/src/selectiondialog.h index 5673f1a..09a28f1 100644 --- a/src/selectiondialog.h +++ b/src/selectiondialog.h @@ -37,6 +37,8 @@ public: std::function on_hide; std::function on_select; Glib::RefPtr start_mark; + + bool shown=false; protected: virtual void resize(); virtual void update_tooltips(); @@ -50,8 +52,6 @@ protected: std::unique_ptr tooltips; std::unordered_map tooltip_texts; std::string last_row; -private: - bool shown=false; }; class SelectionDialog : public SelectionDialogBase { diff --git a/src/source.cc b/src/source.cc index a34755e..1afe104 100644 --- a/src/source.cc +++ b/src/source.cc @@ -8,8 +8,6 @@ #include "filesystem.h" #include "terminal.h" -using namespace std; //TODO: remove - namespace sigc { #ifndef SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE template @@ -219,7 +217,7 @@ Source::View::View(const boost::filesystem::path &file_path, const boost::filesy return; if(mark->get_name()=="insert") { - if(spellcheck_suggestions_dialog_shown) + if(spellcheck_suggestions_dialog && spellcheck_suggestions_dialog->shown) spellcheck_suggestions_dialog->hide(); delayed_spellcheck_suggestions_connection.disconnect(); delayed_spellcheck_suggestions_connection=Glib::signal_timeout().connect([this]() { @@ -233,9 +231,6 @@ Source::View::View(const boost::filesystem::path &file_path, const boost::filesy } if(need_suggestions) { spellcheck_suggestions_dialog=std::unique_ptr(new SelectionDialog(*this, get_buffer()->create_mark(get_buffer()->get_insert()->get_iter()), false)); - spellcheck_suggestions_dialog->on_hide=[this](){ - spellcheck_suggestions_dialog_shown=false; - }; auto word=spellcheck_get_word(get_buffer()->get_insert()->get_iter()); auto suggestions=spellcheck_get_suggestions(word.first, word.second); if(suggestions.size()==0) @@ -250,7 +245,6 @@ Source::View::View(const boost::filesystem::path &file_path, const boost::filesy delayed_tooltips_connection.disconnect(); }; spellcheck_suggestions_dialog->show(); - spellcheck_suggestions_dialog_shown=true; } return false; }, 500); @@ -261,7 +255,7 @@ Source::View::View(const boost::filesystem::path &file_path, const boost::filesy set_info(info); }); - set_tooltip_events(); + set_tooltip_and_dialog_events(); tab_char=Config::get().source.default_tab_char; tab_size=Config::get().source.default_tab_size; @@ -386,7 +380,7 @@ void Source::View::configure() { get_buffer()->remove_tag_by_name("spellcheck_error", get_buffer()->begin(), get_buffer()->end()); } -void Source::View::set_tooltip_events() { +void Source::View::set_tooltip_and_dialog_events() { 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(); @@ -434,14 +428,29 @@ void Source::View::set_tooltip_events() { }, 500); type_tooltips.hide(); diagnostic_tooltips.hide(); + + if(spellcheck_suggestions_dialog && spellcheck_suggestions_dialog->shown) + spellcheck_suggestions_dialog->hide(); + if(autocomplete_dialog && autocomplete_dialog->shown) + autocomplete_dialog->hide(); + if(selection_dialog && selection_dialog->shown) + selection_dialog->hide(); + set_info(info); } }); - + signal_scroll_event().connect([this](GdkEventScroll* event) { delayed_tooltips_connection.disconnect(); type_tooltips.hide(); diagnostic_tooltips.hide(); + delayed_spellcheck_suggestions_connection.disconnect(); + if(spellcheck_suggestions_dialog && spellcheck_suggestions_dialog->shown) + spellcheck_suggestions_dialog->hide(); + if(autocomplete_dialog && autocomplete_dialog->shown) + autocomplete_dialog->hide(); + if(selection_dialog && selection_dialog->shown) + selection_dialog->hide(); return false; }); @@ -449,6 +458,19 @@ void Source::View::set_tooltip_events() { delayed_tooltips_connection.disconnect(); type_tooltips.hide(); diagnostic_tooltips.hide(); + delayed_spellcheck_suggestions_connection.disconnect(); + if(spellcheck_suggestions_dialog && spellcheck_suggestions_dialog->shown) + spellcheck_suggestions_dialog->hide(); + if(autocomplete_dialog && autocomplete_dialog->shown) + autocomplete_dialog->hide(); + return false; + }); + + signal_leave_notify_event().connect([this](GdkEventCrossing*) { + delayed_tooltips_connection.disconnect(); + type_tooltips.hide(); + diagnostic_tooltips.hide(); + delayed_spellcheck_suggestions_connection.disconnect(); return false; }); } @@ -509,7 +531,8 @@ void Source::View::replace_forward(const std::string &replacement) { auto offset=match_start.get_offset(); gtk_source_search_context_replace(search_context, match_start.gobj(), match_end.gobj(), replacement.c_str(), replacement.size(), NULL); - get_buffer()->select_range(get_buffer()->get_iter_at_offset(offset), get_buffer()->get_iter_at_offset(offset+replacement.size())); + Glib::ustring replacement_ustring=replacement; + get_buffer()->select_range(get_buffer()->get_iter_at_offset(offset), get_buffer()->get_iter_at_offset(offset+replacement_ustring.size())); scroll_to(get_buffer()->get_insert()); } } @@ -923,7 +946,7 @@ bool Source::View::find_left_bracket_backward(Gtk::TextIter iter, Gtk::TextIter //Basic indentation bool Source::View::on_key_press_event(GdkEventKey* key) { - if(spellcheck_suggestions_dialog_shown) { + if(spellcheck_suggestions_dialog && spellcheck_suggestions_dialog->shown) { if(spellcheck_suggestions_dialog->on_key_press(key)) return true; } @@ -1227,8 +1250,8 @@ std::pair Source::View::find_tab_char_and_size() { } else if(!iter.ends_line()) { if(tab_count!=last_tab_count) - tab_sizes[abs(tab_count-last_tab_count)]++; - last_tab_diff=abs(tab_count-last_tab_count); + tab_sizes[std::abs(tab_count-last_tab_count)]++; + last_tab_diff=std::abs(tab_count-last_tab_count); last_tab_count=tab_count; last_char=0; } @@ -1282,7 +1305,7 @@ std::pair Source::View::find_tab_char_and_size() { } else if(!iter.ends_line()) { if(tab_count!=last_tab_count) - tab_sizes[abs(tab_count-last_tab_count)]++; + tab_sizes[std::abs(tab_count-last_tab_count)]++; last_tab_count=tab_count; } } diff --git a/src/source.h b/src/source.h index e11a57c..35d6c98 100644 --- a/src/source.h +++ b/src/source.h @@ -85,6 +85,7 @@ namespace Source { std::function goto_next_diagnostic; std::function apply_fix_its; + std::unique_ptr autocomplete_dialog; std::unique_ptr selection_dialog; sigc::connection delayed_tooltips_connection; @@ -114,7 +115,7 @@ namespace Source { virtual void show_type_tooltips(const Gdk::Rectangle &rectangle) {} gdouble on_motion_last_x; gdouble on_motion_last_y; - void set_tooltip_events(); + void set_tooltip_and_dialog_events(); std::string get_line(const Gtk::TextIter &iter); std::string get_line(Glib::RefPtr mark); @@ -143,7 +144,6 @@ namespace Source { bool spellcheck_all=false; std::unique_ptr spellcheck_suggestions_dialog; - bool spellcheck_suggestions_dialog_shown=false; bool last_keyval_is_backspace=false; bool last_keyval_is_return=false; private: diff --git a/src/source_clang.cc b/src/source_clang.cc index f51a9a8..864f318 100644 --- a/src/source_clang.cc +++ b/src/source_clang.cc @@ -422,7 +422,7 @@ void Source::ClangViewParse::show_type_tooltips(const Gdk::Rectangle &rectangle) //Clang indentation. bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) { - if(spellcheck_suggestions_dialog_shown) { + if(spellcheck_suggestions_dialog && spellcheck_suggestions_dialog->shown) { if(spellcheck_suggestions_dialog->on_key_press(key)) return true; } @@ -610,7 +610,7 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) { Source::ClangViewAutocomplete::ClangViewAutocomplete(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path, Glib::RefPtr language): Source::ClangViewParse(file_path, project_path, language), autocomplete_state(AutocompleteState::IDLE) { get_buffer()->signal_changed().connect([this](){ - if(autocomplete_state==AutocompleteState::SHOWN) + if(autocomplete_dialog && autocomplete_dialog->shown) delayed_reparse_connection.disconnect(); else { if(!has_focus()) @@ -621,7 +621,7 @@ Source::ClangViewParse(file_path, project_path, language), autocomplete_state(Au autocomplete_check(); } else { - if(autocomplete_state==AutocompleteState::STARTING) + if(autocomplete_state==AutocompleteState::STARTING || autocomplete_state==AutocompleteState::RESTARTING) autocomplete_state=AutocompleteState::CANCELED; else { auto iter=get_buffer()->get_insert()->get_iter(); @@ -633,19 +633,12 @@ Source::ClangViewParse(file_path, project_path, language), autocomplete_state(Au }); get_buffer()->signal_mark_set().connect([this](const Gtk::TextBuffer::iterator& iterator, const Glib::RefPtr& mark){ if(mark->get_name()=="insert") { - if(autocomplete_state==AutocompleteState::SHOWN) - autocomplete_dialog->hide(); - if(autocomplete_state==AutocompleteState::STARTING) + if(autocomplete_state==AutocompleteState::STARTING || autocomplete_state==AutocompleteState::RESTARTING) autocomplete_state=AutocompleteState::CANCELED; } }); - signal_scroll_event().connect([this](GdkEventScroll* event){ - if(autocomplete_state==AutocompleteState::SHOWN) - autocomplete_dialog->hide(); - return false; - }, false); signal_key_release_event().connect([this](GdkEventKey* key){ - if(autocomplete_state==AutocompleteState::SHOWN) { + if(autocomplete_dialog && autocomplete_dialog->shown) { if(autocomplete_dialog->on_key_release(key)) return true; } @@ -654,9 +647,7 @@ Source::ClangViewParse(file_path, project_path, language), autocomplete_state(Au }, false); signal_focus_out_event().connect([this](GdkEventFocus* event) { - if(autocomplete_state==AutocompleteState::SHOWN) - autocomplete_dialog->hide(); - if(autocomplete_state==AutocompleteState::STARTING) + if(autocomplete_state==AutocompleteState::STARTING || autocomplete_state==AutocompleteState::RESTARTING) autocomplete_state=AutocompleteState::CANCELED; return false; }); @@ -666,6 +657,11 @@ Source::ClangViewParse(file_path, project_path, language), autocomplete_state(Au set_status(""); soft_reparse(); autocomplete_state=AutocompleteState::IDLE; + } + else if(autocomplete_state==AutocompleteState::RESTARTING) { + set_status(""); + soft_reparse(); + autocomplete_state=AutocompleteState::IDLE; autocomplete_restart(); } else { @@ -693,15 +689,13 @@ Source::ClangViewParse(file_path, project_path, language), autocomplete_state(Au } } set_status(""); + autocomplete_state=AutocompleteState::IDLE; if (!autocomplete_dialog_rows.empty()) { - autocomplete_state=AutocompleteState::SHOWN; get_source_buffer()->begin_user_action(); autocomplete_dialog->show(); } - else { - autocomplete_state=AutocompleteState::IDLE; + else soft_reparse(); - } } }); @@ -728,7 +722,7 @@ Source::ClangViewParse(file_path, project_path, language), autocomplete_state(Au bool Source::ClangViewAutocomplete::on_key_press_event(GdkEventKey *key) { last_keyval=key->keyval; - if(autocomplete_state==AutocompleteState::SHOWN) { + if(autocomplete_dialog && autocomplete_dialog->shown) { if(autocomplete_dialog->on_key_press(key)) return true; } @@ -743,7 +737,6 @@ void Source::ClangViewAutocomplete::autocomplete_dialog_setup() { autocomplete_dialog_rows.clear(); autocomplete_dialog->on_hide=[this](){ get_source_buffer()->end_user_action(); - autocomplete_state=AutocompleteState::IDLE; parsed=false; soft_reparse(); }; @@ -759,7 +752,6 @@ void Source::ClangViewAutocomplete::autocomplete_dialog_setup() { } get_buffer()->insert(autocomplete_dialog->start_mark->get_iter(), row); if(hide_window) { - autocomplete_state=AutocompleteState::IDLE; auto para_pos=row.find('('); auto angle_pos=row.find('<'); size_t start_pos=std::string::npos; @@ -793,10 +785,8 @@ void Source::ClangViewAutocomplete::autocomplete_dialog_setup() { else { //new autocomplete after for instance when selecting "std::" auto iter=get_buffer()->get_insert()->get_iter(); - if(iter.backward_char() && *iter==':') { - autocomplete_state=AutocompleteState::IDLE; + if(iter.backward_char() && *iter==':') autocomplete_restart(); - } } } }; @@ -815,14 +805,14 @@ void Source::ClangViewAutocomplete::autocomplete_check() { prefix_mutex.lock(); prefix=sm[3].str(); prefix_mutex.unlock(); - if(autocomplete_state==AutocompleteState::IDLE && (prefix.size()==0 || prefix[0]<'0' || prefix[0]>'9')) + if(prefix.size()==0 || prefix[0]<'0' || prefix[0]>'9') autocomplete(); } else if(boost::regex_match(line, sm, within_namespace)) { prefix_mutex.lock(); prefix=sm[3].str(); prefix_mutex.unlock(); - if(autocomplete_state==AutocompleteState::IDLE && (prefix.size()==0 || prefix[0]<'0' || prefix[0]>'9')) + if(prefix.size()==0 || prefix[0]<'0' || prefix[0]>'9') autocomplete(); } if(autocomplete_state!=AutocompleteState::IDLE) @@ -832,12 +822,13 @@ void Source::ClangViewAutocomplete::autocomplete_check() { void Source::ClangViewAutocomplete::autocomplete() { if(parse_state!=ParseState::PROCESSING) return; - if(autocomplete_state==AutocompleteState::STARTING) { - autocomplete_state=AutocompleteState::CANCELED; - return; - } + if(autocomplete_state==AutocompleteState::CANCELED) + autocomplete_state=AutocompleteState::RESTARTING; + + if(autocomplete_state!=AutocompleteState::IDLE) return; + autocomplete_state=AutocompleteState::STARTING; autocomplete_data.clear(); diff --git a/src/source_clang.h b/src/source_clang.h index 117d8d1..f4d26d6 100644 --- a/src/source_clang.h +++ b/src/source_clang.h @@ -72,7 +72,7 @@ namespace Source { class ClangViewAutocomplete : public ClangViewParse { protected: - enum class AutocompleteState {IDLE, STARTING, CANCELED, SHOWN}; + enum class AutocompleteState {IDLE, STARTING, RESTARTING, CANCELED}; public: class AutoCompleteData { public: @@ -101,7 +101,6 @@ namespace Source { void autocomplete_check(); void autocomplete(); std::vector autocomplete_data; - std::unique_ptr autocomplete_dialog; std::unordered_map autocomplete_dialog_rows; std::vector autocomplete_get_suggestions(const std::string &buffer, int line_number, int column); Glib::Dispatcher autocomplete_done; diff --git a/src/window.cc b/src/window.cc index f7fad76..acc4024 100644 --- a/src/window.cc +++ b/src/window.cc @@ -1,4 +1,3 @@ - #include "window.h" #include "logging.h" #include "config.h" @@ -25,7 +24,7 @@ namespace sigc { Window::Window() : compiling(false) { JDEBUG("start"); set_title("juCi++"); - set_events(Gdk::POINTER_MOTION_MASK|Gdk::FOCUS_CHANGE_MASK|Gdk::SCROLL_MASK); + set_events(Gdk::POINTER_MOTION_MASK|Gdk::FOCUS_CHANGE_MASK|Gdk::SCROLL_MASK|Gdk::LEAVE_NOTIFY_MASK); set_menu_actions(); configure(); set_default_size(Config::get().window.default_size.first, Config::get().window.default_size.second); @@ -411,6 +410,7 @@ void Window::set_menu_actions() { if(notebook.get_current_page()!=-1 && notebook.get_current_view()==view) { view->get_buffer()->place_cursor(view->get_buffer()->get_iter_at_line_index(line, index)); view->scroll_to(view->get_buffer()->get_insert(), 0.0, 1.0, 0.5); + view->delayed_tooltips_connection.disconnect(); } } } @@ -517,11 +517,26 @@ void Window::set_menu_actions() { return; CMake cmake(cmake_path); auto executables = cmake.get_functions_parameters("add_executable"); + + //Attempt to find executable based add_executable files and opened tab boost::filesystem::path executable_path; - if(executables.size()>0 && executables[0].second.size()>0) { - executable_path=executables[0].first.parent_path(); - executable_path+="/"+executables[0].second[0]; + if(notebook.get_current_page()!=-1) { + for(auto &executable: executables) { + if(executable.second.size()>1) { + for(size_t c=1;cfile_path.filename()) { + executable_path=executable.first.parent_path()/executable.second[0]; + break; + } + } + } + if(!executable_path.empty()) + break; + } } + if(executable_path.empty() && executables.size()>0 && executables[0].second.size()>0) + executable_path=executables[0].first.parent_path()/executables[0].second[0]; + if(cmake.project_path!="") { if(executable_path!="") { compiling=true; @@ -591,7 +606,7 @@ void Window::set_menu_actions() { }); } entry_box.hide(); - }); + }, 30); auto entry_it=entry_box.entries.begin(); entry_it->set_placeholder_text("Command"); entry_box.buttons.emplace_back("Run command", [this, entry_it](){