diff --git a/README.md b/README.md index 7740893..5851476 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ towards libclang with speed and ease of use in mind. * Source minimap * Split view * Full UTF-8 support +* Wayland supported with GTK+ 3.20 or newer See [enhancements](https://github.com/cppit/jucipp/labels/enhancement) for planned features. diff --git a/src/debug_clang.cc b/src/debug_clang.cc index b5fe479..6a079a1 100644 --- a/src/debug_clang.cc +++ b/src/debug_clang.cc @@ -159,7 +159,7 @@ void Debug::Clang::start(const std::string &command, const boost::filesystem::pa auto column=line_entry.GetColumn(); if(column==0) column=1; - stop_callback(stream.GetData(), line_entry.GetLine(), column); + stop_callback(filesystem::get_canonical_path(stream.GetData()), line_entry.GetLine(), column); } else stop_callback("", 0, 0); @@ -295,7 +295,7 @@ std::vector Debug::Clang::get_backtrace() { auto column=line_entry.GetColumn(); if(column==0) column=1; - backtrace_frame.file_path=stream.GetData(); + backtrace_frame.file_path=filesystem::get_canonical_path(stream.GetData()); backtrace_frame.line_nr=line_entry.GetLine(); backtrace_frame.line_index=column; } @@ -333,7 +333,7 @@ std::vector Debug::Clang::get_variables() { variable.line_index=1; auto file_spec=declaration.GetFileSpec(); - variable.file_path=file_spec.GetDirectory(); + variable.file_path=filesystem::get_canonical_path(file_spec.GetDirectory()); variable.file_path/=file_spec.GetFilename(); value.GetDescription(stream); @@ -380,7 +380,7 @@ std::string Debug::Clang::get_value(const std::string &variable, const boost::fi if(declaration.IsValid()) { if(declaration.GetLine()==line_nr && (declaration.GetColumn()==0 || declaration.GetColumn()==line_index)) { auto file_spec=declaration.GetFileSpec(); - boost::filesystem::path value_decl_path=file_spec.GetDirectory(); + auto value_decl_path=filesystem::get_canonical_path(file_spec.GetDirectory()); value_decl_path/=file_spec.GetFilename(); if(value_decl_path==file_path) { value.GetDescription(stream); @@ -415,7 +415,7 @@ std::string Debug::Clang::get_return_value(const boost::filesystem::path &file_p if(line_entry.IsValid()) { lldb::SBStream stream; line_entry.GetFileSpec().GetDescription(stream); - if(boost::filesystem::path(stream.GetData())==file_path && line_entry.GetLine()==line_nr && + if(filesystem::get_canonical_path(stream.GetData())==file_path && line_entry.GetLine()==line_nr && (line_entry.GetColumn()==0 || line_entry.GetColumn()==line_index)) { lldb::SBStream stream; thread_return_value.GetDescription(stream); @@ -461,11 +461,9 @@ void Debug::Clang::remove_breakpoint(const boost::filesystem::path &file_path, i auto line_entry=breakpoint.GetLocationAtIndex(l_index).GetAddress().GetLineEntry(); if(line_entry.GetLine()==static_cast(line_nr_try)) { auto file_spec=line_entry.GetFileSpec(); - boost::filesystem::path breakpoint_path=file_spec.GetDirectory(); + auto breakpoint_path=filesystem::get_canonical_path(file_spec.GetDirectory()); breakpoint_path/=file_spec.GetFilename(); - boost::system::error_code ec; - breakpoint_path = boost::filesystem::canonical(breakpoint_path, ec); - if(!ec && breakpoint_path==file_path) { + if(breakpoint_path==file_path) { if(!target.BreakpointDelete(breakpoint.GetID())) Terminal::get().async_print("Error (debug): Could not delete breakpoint at: "+file_path.string()+":"+std::to_string(line_nr)+'\n', true); return; diff --git a/src/debug_clang.h b/src/debug_clang.h index 3be3c1b..c47a095 100644 --- a/src/debug_clang.h +++ b/src/debug_clang.h @@ -16,7 +16,7 @@ namespace Debug { public: uint32_t index; std::string module_filename; - std::string file_path; + boost::filesystem::path file_path; std::string function_name; int line_nr; int line_index; diff --git a/src/filesystem.cc b/src/filesystem.cc index 63c5bdd..cc6f353 100644 --- a/src/filesystem.cc +++ b/src/filesystem.cc @@ -179,3 +179,22 @@ boost::filesystem::path filesystem::find_file_in_path_parents(const std::string current_path=current_path.parent_path(); } } + +boost::filesystem::path filesystem::get_canonical_path(const boost::filesystem::path &path) noexcept { + if(path.is_absolute()) { + bool is_canonical=true; + for(auto &str: path) { + if(str==".." || str==".") { + is_canonical=false; + break; + } + } + if(is_canonical) + return path; + } + boost::system::error_code ec; + auto canonical_path=boost::filesystem::canonical(path, ec); + if(ec) + return path; + return canonical_path; +} diff --git a/src/filesystem.h b/src/filesystem.h index 74a82aa..2fd60fe 100644 --- a/src/filesystem.h +++ b/src/filesystem.h @@ -31,5 +31,8 @@ public: static bool file_in_path(const boost::filesystem::path &file_path, const boost::filesystem::path &path); static boost::filesystem::path find_file_in_path_parents(const std::string &file_name, const boost::filesystem::path &path); + + ///Attempts to get canonical path, if not, return the path parameter + static boost::filesystem::path get_canonical_path(const boost::filesystem::path &path) noexcept; }; #endif // JUCI_FILESYSTEM_H_ diff --git a/src/notebook.cc b/src/notebook.cc index 3f6dc8d..5df5de2 100644 --- a/src/notebook.cc +++ b/src/notebook.cc @@ -163,7 +163,7 @@ void Notebook::open(const boost::filesystem::path &file_path, size_t notebook_in else view->scroll_to(view->get_buffer()->get_insert()); if(!show_tooltips) - view->delayed_tooltips_connection.disconnect(); + view->hide_tooltips(); } }; source_views.back()->on_update_status=[this](Source::View* view, const std::string &status_text) { @@ -444,6 +444,8 @@ std::pair Notebook::get_notebook_page(size_t index) { void Notebook::set_current_view(Source::View *view) { intermediate_view=nullptr; if(current_view!=view) { + if(auto view=get_current_view()) + view->hide_dialogs(); current_view=view; if(on_change_page) on_change_page(view); diff --git a/src/project.cc b/src/project.cc index 2a31607..fcca09b 100644 --- a/src/project.cc +++ b/src/project.cc @@ -385,7 +385,7 @@ void Project::Clang::debug_backtrace() { if(frame.file_path.empty()) row+=" - "+Glib::Markup::escape_text(frame.function_name); else { - auto file_path=boost::filesystem::path(frame.file_path).filename().string(); + auto file_path=frame.file_path.filename().string(); row+=":"+Glib::Markup::escape_text(file_path)+":"+std::to_string(frame.line_nr)+" - "+Glib::Markup::escape_text(frame.function_name); } (*rows)[row]=frame; @@ -475,6 +475,7 @@ void Project::Clang::debug_show_variables() { } }; + view->hide_tooltips(); view->selection_dialog->show(); } } diff --git a/src/selectiondialog.cc b/src/selectiondialog.cc index 2116057..d9f5784 100644 --- a/src/selectiondialog.cc +++ b/src/selectiondialog.cc @@ -43,48 +43,36 @@ void ListViewText::clear() { list_store.reset(); } -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 - window=std::unique_ptr(new Gtk::Dialog()); - +SelectionDialogBase::SelectionDialogBase(Gtk::TextView& text_view, Glib::RefPtr start_mark, bool show_search_entry, bool use_markup): + text_view(text_view), window(Gtk::WindowType::WINDOW_POPUP), list_view_text(use_markup), start_mark(start_mark), show_search_entry(show_search_entry) { auto g_application=g_application_get_default(); auto gio_application=Glib::wrap(g_application, true); auto application=Glib::RefPtr::cast_static(gio_application); - window->set_transient_for(*application->get_active_window()); + window.set_transient_for(*application->get_active_window()); + + window.set_type_hint(Gdk::WindowTypeHint::WINDOW_TYPE_HINT_COMBO); list_view_text.set_search_entry(search_entry); - window->set_default_size(0, 0); - window->property_decorated()=false; - window->set_skip_taskbar_hint(true); + window.set_default_size(0, 0); + window.property_decorated()=false; + window.set_skip_taskbar_hint(true); + scrolled_window.set_policy(Gtk::PolicyType::POLICY_AUTOMATIC, Gtk::PolicyType::POLICY_AUTOMATIC); + scrolled_window.add(list_view_text); + if(show_search_entry) + vbox.pack_start(search_entry, false, false); + vbox.pack_start(scrolled_window, true, true); + window.add(vbox); + list_view_text.signal_realize().connect([this](){ resize(); }); - list_view_text.signal_event_after().connect([this](GdkEvent* event){ - if(event->type==GDK_KEY_PRESS || event->type==GDK_BUTTON_PRESS) - cursor_changed(); + list_view_text.signal_cursor_changed().connect([this] { + cursor_changed(); }); - if(show_search_entry) { - search_entry.signal_event_after().connect([this](GdkEvent* event){ - if(event->type==GDK_KEY_PRESS || event->type==GDK_BUTTON_PRESS) - cursor_changed(); - }); - } - - scrolled_window.add(list_view_text); - if(!show_search_entry) - window->add(scrolled_window); - else { - auto dialog=static_cast(window.get()); - dialog->get_vbox()->pack_start(search_entry, false, false); - dialog->get_vbox()->pack_start(scrolled_window, true, true); - } } void SelectionDialogBase::cursor_changed() { @@ -112,7 +100,7 @@ void SelectionDialogBase::add_row(const std::string& row) { void SelectionDialogBase::show() { shown=true; move(); - window->show_all(); + window.show_all(); if(list_view_text.get_model()->children().size()>0) { if(!list_view_text.get_selection()->get_selected()) { @@ -139,7 +127,7 @@ void SelectionDialogBase::hide() { if(!shown) return; shown=false; - window->hide(); + window.hide(); if(on_hide) on_hide(); list_view_text.clear(); @@ -156,7 +144,7 @@ void SelectionDialogBase::move() { text_view.buffer_to_window_coords(Gtk::TextWindowType::TEXT_WINDOW_TEXT, buffer_x, buffer_y, window_x, window_y); int root_x, root_y; text_view.get_window(Gtk::TextWindowType::TEXT_WINDOW_TEXT)->get_root_coords(window_x, window_y, root_x, root_y); - window->move(root_x, root_y+1); //TODO: replace 1 with some margin + window.move(root_x, root_y+1); //TODO: replace 1 with some margin } void SelectionDialogBase::resize() { @@ -178,7 +166,7 @@ void SelectionDialogBase::resize() { int window_height=std::min(row_height*static_cast(list_view_text.get_model()->children().size()), row_height*10); if(show_search_entry) window_height+=search_entry.get_height(); - window->resize(row_width+1, window_height); + window.resize(row_width+1, window_height); } } @@ -221,39 +209,16 @@ SelectionDialog::SelectionDialog(Gtk::TextView& text_view, Glib::RefPtrtype==GDK_KEY_PRESS) { - auto key=reinterpret_cast(event); - if(key->keyval==GDK_KEY_Down && list_view_text.get_model()->children().size()>0) { - auto it=list_view_text.get_selection()->get_selected(); - if(it) { - it++; - if(it) - list_view_text.set_cursor(list_view_text.get_model()->get_path(it)); - } - return true; - } - if(key->keyval==GDK_KEY_Up && list_view_text.get_model()->children().size()>0) { - auto it=list_view_text.get_selection()->get_selected(); - if(it) { - it--; - if(it) - list_view_text.set_cursor(list_view_text.get_model()->get_path(it)); - } - return true; - } - } - return false; - }); - auto activate=[this](){ auto it=list_view_text.get_selection()->get_selected(); if(on_select && it) { std::string row; it->get_value(0, row); + hide(); on_select(row, true); } - hide(); + else + hide(); }; search_entry.signal_activate().connect([this, activate](){ activate(); @@ -261,11 +226,6 @@ SelectionDialog::SelectionDialog(Gtk::TextView& text_view, Glib::RefPtrsignal_focus_out_event().connect([this](GdkEventFocus*){ - hide(); - return true; - }); } bool SelectionDialog::on_key_press(GdkEventKey* key) { @@ -278,7 +238,7 @@ bool SelectionDialog::on_key_press(GdkEventKey* key) { } return true; } - if(key->keyval==GDK_KEY_Up && list_view_text.get_model()->children().size()>0) { + else if(key->keyval==GDK_KEY_Up && list_view_text.get_model()->children().size()>0) { auto it=list_view_text.get_selection()->get_selected(); if(it) { it--; @@ -287,15 +247,35 @@ bool SelectionDialog::on_key_press(GdkEventKey* key) { } return true; } - if(key->keyval==GDK_KEY_Return || key->keyval==GDK_KEY_ISO_Left_Tab || key->keyval==GDK_KEY_Tab) { + else if(key->keyval==GDK_KEY_Return || key->keyval==GDK_KEY_ISO_Left_Tab || key->keyval==GDK_KEY_Tab) { auto it=list_view_text.get_selection()->get_selected(); auto column=list_view_text.get_column(0); list_view_text.row_activated(list_view_text.get_model()->get_path(it), *column); return true; } - hide(); - if(key->keyval==GDK_KEY_Escape) + else if(key->keyval==GDK_KEY_Escape) { + hide(); + return true; + } + else if(key->keyval==GDK_KEY_Left || key->keyval==GDK_KEY_Right) { + hide(); + return false; + } + else if(key->keyval==GDK_KEY_BackSpace) { + auto length=search_entry.get_text_length(); + if(length>0) + search_entry.delete_text(length-1, length); return true; + } + else { + gunichar unicode=gdk_keyval_to_unicode(key->keyval); + if(unicode>=32 && unicode!=126) { + int length=search_entry.get_text_length(); + auto ustr=Glib::ustring(1, unicode); + search_entry.insert_text(ustr, ustr.bytes(), length); + return true; + } + } return false; } @@ -347,16 +327,13 @@ void CompletionDialog::select(bool hide_window) { row_in_entry=true; auto it=list_view_text.get_selection()->get_selected(); - if(it) { + if(on_select && it) { std::string row; it->get_value(0, row); - if(on_select) - on_select(row, hide_window); + on_select(row, hide_window); } - - if(hide_window) { + if(hide_window) hide(); - } } bool CompletionDialog::on_key_release(GdkEventKey* key) { diff --git a/src/selectiondialog.h b/src/selectiondialog.h index fa49c12..e648779 100644 --- a/src/selectiondialog.h +++ b/src/selectiondialog.h @@ -44,8 +44,8 @@ protected: void resize(); Gtk::TextView& text_view; - - std::unique_ptr window; + Gtk::Window window; + Gtk::VBox vbox; Gtk::ScrolledWindow scrolled_window; ListViewText list_view_text; Gtk::Entry search_entry; diff --git a/src/source.cc b/src/source.cc index 61045f5..0e2b1ca 100644 --- a/src/source.cc +++ b/src/source.cc @@ -533,6 +533,10 @@ void Source::View::configure() { } void Source::View::set_tooltip_and_dialog_events() { + 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(); @@ -593,28 +597,14 @@ void Source::View::set_tooltip_and_dialog_events() { }); 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->hide(); - if(autocomplete_dialog) - autocomplete_dialog->hide(); - if(selection_dialog) - selection_dialog->hide(); + hide_tooltips(); + hide_dialogs(); return false; }); signal_focus_out_event().connect([this](GdkEventFocus* event) { - delayed_tooltips_connection.disconnect(); - type_tooltips.hide(); - diagnostic_tooltips.hide(); + hide_tooltips(); delayed_spellcheck_suggestions_connection.disconnect(); - if(spellcheck_suggestions_dialog) - spellcheck_suggestions_dialog->hide(); - if(autocomplete_dialog) - autocomplete_dialog->hide(); return false; }); @@ -857,6 +847,22 @@ void Source::View::place_cursor_at_line_index(int line, int index) { get_buffer()->place_cursor(get_buffer()->get_iter_at_line_index(line, index)); } +void Source::View::hide_tooltips() { + delayed_tooltips_connection.disconnect(); + type_tooltips.hide(); + diagnostic_tooltips.hide(); +} + +void Source::View::hide_dialogs() { + delayed_spellcheck_suggestions_connection.disconnect(); + if(spellcheck_suggestions_dialog) + spellcheck_suggestions_dialog->hide(); + if(selection_dialog) + selection_dialog->hide(); + if(autocomplete_dialog) + autocomplete_dialog->hide(); +} + void Source::View::set_status(const std::string &status) { this->status=status; if(on_update_status) @@ -1155,7 +1161,10 @@ bool Source::View::on_key_press_event(GdkEventKey* key) { if(spellcheck_suggestions_dialog->on_key_press(key)) return true; } - + if(selection_dialog && selection_dialog->shown) { + if(selection_dialog->on_key_press(key)) + return true; + } if(autocomplete_dialog && autocomplete_dialog->shown) { if(autocomplete_dialog->on_key_press(key)) return true; diff --git a/src/source.h b/src/source.h index 5acfde1..1941220 100644 --- a/src/source.h +++ b/src/source.h @@ -86,12 +86,14 @@ namespace Source { std::unique_ptr autocomplete_dialog; std::unique_ptr selection_dialog; Gtk::TextIter get_iter_for_dialog(); - sigc::connection delayed_tooltips_connection; std::function scroll_to_cursor_delayed=[](View* view, bool center, bool show_tooltips) {}; void place_cursor_at_line_offset(int line, int offset); void place_cursor_at_line_index(int line, int index); + void hide_tooltips(); + void hide_dialogs(); + std::function on_update_status; std::function on_update_info; void set_status(const std::string &status); @@ -115,6 +117,7 @@ namespace Source { bool parsed=false; Tooltips diagnostic_tooltips; Tooltips type_tooltips; + sigc::connection delayed_tooltips_connection; virtual void show_diagnostic_tooltips(const Gdk::Rectangle &rectangle) {} virtual void show_type_tooltips(const Gdk::Rectangle &rectangle) {} gdouble on_motion_last_x=0.0; diff --git a/src/source_clang.cc b/src/source_clang.cc index 23beff5..084bf66 100644 --- a/src/source_clang.cc +++ b/src/source_clang.cc @@ -39,8 +39,6 @@ Source::View(file_path, language) { get_buffer()->signal_changed().connect([this]() { soft_reparse(); - type_tooltips.hide(); - diagnostic_tooltips.hide(); }); } @@ -85,8 +83,7 @@ void Source::ClangViewParse::configure() { } void Source::ClangViewParse::parse_initialize() { - type_tooltips.hide(); - diagnostic_tooltips.hide(); + hide_tooltips(); parsed=false; if(parse_thread.joinable()) parse_thread.join(); @@ -525,12 +522,12 @@ Source::ClangViewParse(file_path, language), autocomplete_state(AutocompleteStat autocomplete_state=AutocompleteState::CANCELED; } }); + signal_key_release_event().connect([this](GdkEventKey* key){ if(autocomplete_dialog && autocomplete_dialog->shown) { if(autocomplete_dialog->on_key_release(key)) return true; } - return false; }, false); diff --git a/src/terminal.cc b/src/terminal.cc index 176b6d3..edbe55a 100644 --- a/src/terminal.cc +++ b/src/terminal.cc @@ -391,16 +391,15 @@ bool Terminal::on_key_press_event(GdkEventKey *event) { if(processes.size()>0 || debug_is_running) { get_buffer()->place_cursor(get_buffer()->end()); auto unicode=gdk_keyval_to_unicode(event->keyval); - char chr=static_cast(unicode); - if(unicode>=32 && unicode<=126) { - stdin_buffer+=chr; + if(unicode>=32 && unicode!=126) { + stdin_buffer+=unicode; get_buffer()->insert_at_cursor(stdin_buffer.substr(stdin_buffer.size()-1)); } else if(event->keyval==GDK_KEY_BackSpace) { if(stdin_buffer.size()>0 && get_buffer()->get_char_count()>0) { auto iter=get_buffer()->end(); iter--; - stdin_buffer.pop_back(); + stdin_buffer.erase(stdin_buffer.size()-1); get_buffer()->erase(iter, get_buffer()->end()); } } diff --git a/src/terminal.h b/src/terminal.h index 832132c..bc3073e 100644 --- a/src/terminal.h +++ b/src/terminal.h @@ -79,7 +79,7 @@ private: std::vector > processes; std::mutex processes_mutex; - std::string stdin_buffer; + Glib::ustring stdin_buffer; std::unordered_set in_progresses; std::mutex in_progresses_mutex; diff --git a/src/tooltips.cc b/src/tooltips.cc index c308228..f3815fb 100644 --- a/src/tooltips.cc +++ b/src/tooltips.cc @@ -53,11 +53,9 @@ void Tooltip::adjust(bool disregard_drawn) { auto application=Glib::RefPtr::cast_static(gio_application); window->set_transient_for(*application->get_active_window()); + window->set_type_hint(Gdk::WindowTypeHint::WINDOW_TYPE_HINT_TOOLTIP); + window->set_events(Gdk::POINTER_MOTION_MASK); - window->signal_motion_notify_event().connect([this](GdkEventMotion* event){ - window->hide(); - return false; - }); window->property_decorated()=false; window->set_accept_focus(false); window->set_skip_taskbar_hint(true); diff --git a/src/window.cc b/src/window.cc index da0e61a..21980b1 100644 --- a/src/window.cc +++ b/src/window.cc @@ -146,6 +146,12 @@ Window::Window() { EntryBox::get().hide(); }; + signal_focus_out_event().connect([](GdkEventFocus *event) { + if(auto view=Notebook::get().get_current_view()) + view->hide_dialogs(); + return false; + }); + about.signal_response().connect([this](int d){ about.hide(); }); @@ -525,7 +531,7 @@ void Window::set_menu_actions() { auto view=Notebook::get().get_current_view(); view->place_cursor_at_line_index(offset.line, offset.index); view->scroll_to(view->get_buffer()->get_insert(), 0.0, 1.0, 0.5); - view->delayed_tooltips_connection.disconnect(); + view->hide_tooltips(); }; view->selection_dialog->show(); } @@ -548,7 +554,7 @@ void Window::set_menu_actions() { auto offset=rows->at(selected); view->get_buffer()->place_cursor(view->get_buffer()->get_iter_at_line_index(offset.line-1, offset.index-1)); view->scroll_to(view->get_buffer()->get_insert(), 0.0, 1.0, 0.5); - view->delayed_tooltips_connection.disconnect(); + view->hide_tooltips(); }; view->selection_dialog->show(); }