diff --git a/src/source.cc b/src/source.cc index 4bc22f4..8ff9921 100644 --- a/src/source.cc +++ b/src/source.cc @@ -272,6 +272,117 @@ Source::View::View(const boost::filesystem::path &file_path, Glib::RefPtrget_id()=="markdown") { + // The style file currently has no options, but checking if it exists + format_style=[this](bool continue_without_style_file) { + bool has_style_file=false; + auto style_file_search_path=this->file_path.parent_path(); + while(true) { + if(boost::filesystem::exists(style_file_search_path/".markdown-format")) { + has_style_file=true; + break; + } + if(style_file_search_path==style_file_search_path.root_directory()) + break; + style_file_search_path=style_file_search_path.parent_path(); + } + if(!has_style_file && !continue_without_style_file) + return; + + auto special_character=[](Gtk::TextIter iter) { + if(*iter=='*' || *iter=='#' || *iter=='<' || *iter=='>' || *iter==' ' || *iter=='=' || *iter=='`' || *iter=='-') + return true; + // Tests if a line starts with for instance: 2. + if(*iter>='0' && *iter<='9' && iter.forward_char() && + *iter=='.' && iter.forward_char() && + *iter==' ') + return true; + return false; + }; + + get_buffer()->begin_user_action(); + cleanup_whitespace_characters(); + + auto iter=get_buffer()->begin(); + size_t last_space_offset=-1; + bool headline=false; + bool monospace=false; + bool script=false; + bool html_tag=false; + int square_brackets=0; + do { + if(iter.starts_line()) { + last_space_offset=-1; + auto next_line_iter=iter; + if(*iter=='#' || (next_line_iter.forward_line() && *next_line_iter=='=')) + headline=true; + else + headline=false; + auto test_iter=iter; + if(*test_iter=='`' && test_iter.forward_char() && + *test_iter=='`' && test_iter.forward_char() && + *test_iter=='`') { + script=!script; + iter.forward_chars(2); + continue; + } + } + if(!script && *iter=='`') + monospace=!monospace; + if(!script && !monospace) { + if(*iter=='<') + html_tag=true; + else if(*iter=='>') + html_tag=false; + else if(*iter=='[') + ++square_brackets; + else if(*iter==']') + --square_brackets; + } + if(!headline && !script && !monospace && !html_tag && square_brackets==0) { + if(*iter==' ' && iter.get_line_offset()<80) + last_space_offset=iter.get_offset(); + // Insert newline on long lines + else if((*iter==' ' || iter.ends_line()) && iter.get_line_offset()>=80 && last_space_offset!=static_cast(-1)) { + auto stored_iter=iter; + iter=get_buffer()->get_iter_at_offset(last_space_offset); + auto next_iter=iter; + next_iter.forward_char(); + // Do not add newline if the next iter is a special character + if(special_character(next_iter)) { + iter=stored_iter; + if(*iter==' ') + last_space_offset=iter.get_offset(); + continue; + } + iter=get_buffer()->erase(iter, next_iter); + iter=get_buffer()->insert(iter, "\n"); + iter.backward_char(); + } + // Remove newline on short lines + else if(iter.ends_line() && !iter.starts_line() && iter.get_line_offset()<80) { + auto next_line_iter=iter; + // Do not remove newline if the next line for instance is a header + if(next_line_iter.forward_char() && !next_line_iter.ends_line() && !special_character(next_line_iter)) { + auto end_word_iter=next_line_iter; + // Do not remove newline if the word on the next line is too long + size_t diff=0; + while(*end_word_iter!=' ' && !end_word_iter.ends_line() && end_word_iter.forward_char()) + ++diff; + if(iter.get_line_offset()+diff+1<80) { + iter=get_buffer()->erase(iter, next_line_iter); + iter=get_buffer()->insert(iter, " "); + iter.backward_char(); + if(iter.get_line_offset()<80) + last_space_offset=iter.get_offset(); + } + } + } + } + } while(iter.forward_char()); + get_buffer()->end_user_action(); + }; + } #ifndef __APPLE__ set_tab_width(4); //Visual size of a \t hardcoded to be equal to visual size of 4 spaces. Buggy on OS X @@ -400,6 +511,7 @@ Source::View::View(const boost::filesystem::path &file_path, Glib::RefPtrbegin_not_undoable_action(); get_buffer()->erase(get_buffer()->begin(), get_buffer()->end()); bool status=true; @@ -414,6 +526,7 @@ bool Source::View::load() { } } get_source_buffer()->end_not_undoable_action(); + disable_spellcheck=false; boost::system::error_code ec; last_write_time=boost::filesystem::last_write_time(file_path, ec); diff --git a/src/source_spellcheck.cc b/src/source_spellcheck.cc index 598109f..cb60a03 100644 --- a/src/source_spellcheck.cc +++ b/src/source_spellcheck.cc @@ -51,6 +51,15 @@ Source::SpellCheckView::SpellCheckView() : Gsv::View() { auto iter=get_buffer()->get_insert()->get_iter(); if(!is_word_iter(iter) && !iter.starts_line()) iter.backward_char(); + + if(disable_spellcheck) { + if(is_word_iter(iter)) { + auto word=get_word(iter); + get_buffer()->remove_tag(spellcheck_error_tag, word.first, word.second); + } + return; + } + if(!is_code_iter(iter)) { if(last_keyval==GDK_KEY_Return || last_keyval==GDK_KEY_KP_Enter) { auto previous_line_iter=iter; @@ -136,7 +145,8 @@ Source::SpellCheckView::SpellCheckView() : Gsv::View() { get_buffer()->signal_insert().connect([this](const Gtk::TextIter &start_iter, const Glib::ustring &inserted_string, int) { if(spellcheck_checker==nullptr) return; - if(inserted_string.size()<=1) + + if(!disable_spellcheck) return; auto iter=start_iter; diff --git a/src/source_spellcheck.h b/src/source_spellcheck.h index 319619d..b456485 100644 --- a/src/source_spellcheck.h +++ b/src/source_spellcheck.h @@ -18,6 +18,7 @@ namespace Source { void remove_spellcheck_errors(); void goto_next_spellcheck_error(); + bool disable_spellcheck=false; protected: bool is_code_iter(const Gtk::TextIter &iter); bool spellcheck_all=false; diff --git a/src/window.cc b/src/window.cc index 9486a2c..f6d514a 100644 --- a/src/window.cc +++ b/src/window.cc @@ -442,7 +442,9 @@ void Window::set_menu_actions() { if(auto view=Notebook::get().get_current_view()) { auto undo_manager = view->get_source_buffer()->get_undo_manager(); if (undo_manager->can_undo()) { + view->disable_spellcheck=true; undo_manager->undo(); + view->disable_spellcheck=false; view->scroll_to(view->get_buffer()->get_insert()); } } @@ -451,7 +453,9 @@ void Window::set_menu_actions() { if(auto view=Notebook::get().get_current_view()) { auto undo_manager = view->get_source_buffer()->get_undo_manager(); if(undo_manager->can_redo()) { + view->disable_spellcheck=true; undo_manager->redo(); + view->disable_spellcheck=false; view->scroll_to(view->get_buffer()->get_insert()); } } @@ -461,8 +465,11 @@ void Window::set_menu_actions() { auto widget=get_focus(); if(auto entry=dynamic_cast(widget)) entry->cut_clipboard(); - else if(auto view=Notebook::get().get_current_view()) + else if(auto view=Notebook::get().get_current_view()) { + view->disable_spellcheck=true; view->get_buffer()->cut_clipboard(Gtk::Clipboard::get()); + view->disable_spellcheck=false; + } }); menu.add_action("edit_copy", [this]() { auto widget=get_focus(); @@ -475,8 +482,11 @@ void Window::set_menu_actions() { auto widget=get_focus(); if(auto entry=dynamic_cast(widget)) entry->paste_clipboard(); - else if(auto view=Notebook::get().get_current_view()) + else if(auto view=Notebook::get().get_current_view()) { + view->disable_spellcheck=true; view->paste(); + view->disable_spellcheck=false; + } }); menu.add_action("edit_find", [this]() { @@ -530,8 +540,11 @@ void Window::set_menu_actions() { }); menu.add_action("source_indentation_auto_indent_buffer", [this]() { auto view=Notebook::get().get_current_view(); - if(view && view->format_style) + if(view && view->format_style) { + view->disable_spellcheck=true; view->format_style(true); + view->disable_spellcheck=false; + } }); menu.add_action("source_goto_line", [this]() {