@ -1,11 +1,16 @@
# include "source.h"
# include "config.h"
# include <boost/property_tree/json_parser.hpp>
# include <algorithm>
# include <gtksourceview/gtksource.h>
# include <iostream>
# include "filesystem.h"
# include "terminal.h"
# include "info.h"
# include <gtksourceview/gtksource.h>
# include <boost/property_tree/json_parser.hpp>
# include <boost/spirit/home/qi/char.hpp>
# include <boost/spirit/home/qi/operator.hpp>
# include <boost/spirit/home/qi/string.hpp>
# include <iostream>
# include <numeric>
# include <set>
namespace sigc {
# ifndef SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE
@ -79,10 +84,15 @@ std::string Source::FixIt::string(Glib::RefPtr<Gtk::TextBuffer> buffer) {
//////////////
//// View ////
//////////////
const REGEX_NS : : regex Source : : View : : bracket_regex ( " ^([ \\ t]*).* \\ { *$ " ) ;
const REGEX_NS : : regex Source : : View : : no_bracket_statement_regex ( " ^([ \\ t]*)(if|for|else if|while) * \\ (.*[^;}] *$ " ) ;
const REGEX_NS : : regex Source : : View : : no_bracket_no_para_statement_regex ( " ^([ \\ t]*)(else) *$ " ) ;
AspellConfig * Source : : View : : spellcheck_config = NULL ;
Source : : View : : View ( const boost : : filesystem : : path & file_path , Glib : : RefPtr < Gsv : : Language > language ) : file_path ( file_path ) , language ( language ) {
get_source_buffer ( ) - > begin_not_undoable_action ( ) ;
last_read_time = std : : chrono : : system_clock : : to_time_t ( std : : chrono : : system_clock : : now ( ) ) ;
if ( language ) {
if ( filesystem : : read_non_utf8 ( file_path , get_buffer ( ) ) = = - 1 )
Terminal : : get ( ) . print ( " Warning: " + file_path . string ( ) + " is not a valid UTF-8 file. Saving might corrupt the file. \n " ) ;
@ -252,10 +262,10 @@ Source::View::View(const boost::filesystem::path &file_path, Glib::RefPtr<Gsv::L
for ( auto & suggestion : suggestions )
spellcheck_suggestions_dialog - > add_row ( suggestion ) ;
spellcheck_suggestions_dialog - > on_select = [ this , word ] ( const std : : string & selected , bool hide_window ) {
get_source_ buffer ( ) - > begin_user_action ( ) ;
get_buffer ( ) - > begin_user_action ( ) ;
get_buffer ( ) - > erase ( word . first , word . second ) ;
get_buffer ( ) - > insert ( get_buffer ( ) - > get_insert ( ) - > get_iter ( ) , selected ) ;
get_source_ buffer ( ) - > end_user_action ( ) ;
get_buffer ( ) - > end_user_action ( ) ;
delayed_tooltips_connection . disconnect ( ) ;
} ;
spellcheck_suggestions_dialog - > show ( ) ;
@ -271,10 +281,6 @@ Source::View::View(const boost::filesystem::path &file_path, Glib::RefPtr<Gsv::L
set_tooltip_and_dialog_events ( ) ;
bracket_regex = boost : : regex ( " ^([ \\ t]*).* \\ { *$ " ) ;
no_bracket_statement_regex = boost : : regex ( " ^([ \\ t]*)(if|for|else if|while) * \\ (.*[^;}] *$ " ) ;
no_bracket_no_para_statement_regex = boost : : regex ( " ^([ \\ t]*)(else) *$ " ) ;
if ( language & & ( language - > get_id ( ) = = " chdr " | | language - > get_id ( ) = = " cpphdr " | | language - > get_id ( ) = = " c " | |
language - > get_id ( ) = = " cpp " | | language - > get_id ( ) = = " objc " | | language - > get_id ( ) = = " java " | |
language - > get_id ( ) = = " js " | | language - > get_id ( ) = = " ts " | | language - > get_id ( ) = = " proto " | |
@ -321,26 +327,17 @@ Source::View::View(const boost::filesystem::path &file_path, Glib::RefPtr<Gsv::L
auto exit_status = Terminal : : get ( ) . process ( stdin_stream , stdout_stream , command , this - > file_path . parent_path ( ) ) ;
if ( exit_status = = 0 ) {
get_source_ buffer ( ) - > begin_user_action ( ) ;
get_buffer ( ) - > begin_user_action ( ) ;
auto iter = get_buffer ( ) - > get_insert ( ) - > get_iter ( ) ;
auto cursor_line_nr = iter . get_line ( ) ;
auto cursor_line_offset = iter . get_line_offset ( ) ;
get_buffer ( ) - > set_text ( stdout_stream . str ( ) ) ;
get_source_ buffer ( ) - > end_user_action ( ) ;
get_buffer ( ) - > end_user_action ( ) ;
cursor_line_nr = std : : min ( cursor_line_nr , get_buffer ( ) - > get_line_count ( ) - 1 ) ;
if ( cursor_line_nr > = 0 ) {
iter = get_buffer ( ) - > get_iter_at_line ( cursor_line_nr ) ;
for ( int c = 0 ; c < cursor_line_offset ; c + + ) {
if ( iter . ends_line ( ) )
break ;
iter . forward_char ( ) ;
}
get_buffer ( ) - > place_cursor ( iter ) ;
place_cursor_at_line_offset ( cursor_line_nr , cursor_line_offset ) ;
scroll_to_cursor_delayed ( this , true , false ) ;
}
}
} ;
}
@ -374,6 +371,70 @@ void Source::View::set_tab_char_and_size(char tab_char, unsigned tab_size) {
tab + = tab_char ;
}
Gsv : : DrawSpacesFlags Source : : View : : parse_show_whitespace_characters ( const std : : string & text ) {
namespace qi = boost : : spirit : : qi ;
qi : : symbols < char , Gsv : : DrawSpacesFlags > options ;
options . add
( " space " , Gsv : : DRAW_SPACES_SPACE )
( " tab " , Gsv : : DRAW_SPACES_TAB )
( " newline " , Gsv : : DRAW_SPACES_NEWLINE )
( " nbsp " , Gsv : : DRAW_SPACES_NBSP )
( " leading " , Gsv : : DRAW_SPACES_LEADING )
( " text " , Gsv : : DRAW_SPACES_TEXT )
( " trailing " , Gsv : : DRAW_SPACES_TRAILING )
( " all " , Gsv : : DRAW_SPACES_ALL ) ;
std : : set < Gsv : : DrawSpacesFlags > out ;
// parse comma-separated list of options
qi : : phrase_parse ( text . begin ( ) , text . end ( ) , options % ' , ' , qi : : space , out ) ;
return out . count ( Gsv : : DRAW_SPACES_ALL ) > 0 ?
Gsv : : DRAW_SPACES_ALL :
static_cast < Gsv : : DrawSpacesFlags > ( std : : accumulate ( out . begin ( ) , out . end ( ) , 0 ) ) ;
}
bool Source : : View : : save ( const std : : vector < Source : : View * > & views ) {
if ( file_path . empty ( ) | | ! get_buffer ( ) - > get_modified ( ) )
return false ;
//Remove trailing whitespace characters on save, and add trailing newline if missing
if ( Config : : get ( ) . source . cleanup_whitespace_characters ) {
auto buffer = get_buffer ( ) ;
buffer - > begin_user_action ( ) ;
for ( int line = 0 ; line < buffer - > get_line_count ( ) ; line + + ) {
auto iter = buffer - > get_iter_at_line ( line ) ;
auto end_iter = iter ;
while ( ! end_iter . ends_line ( ) )
end_iter . forward_char ( ) ;
if ( iter = = end_iter )
continue ;
iter = end_iter ;
while ( ! iter . starts_line ( ) & & ( * iter = = ' ' | | * iter = = ' \t ' | | iter . ends_line ( ) ) )
iter . backward_char ( ) ;
if ( * iter ! = ' ' & & * iter ! = ' \t ' )
iter . forward_char ( ) ;
if ( iter = = end_iter )
continue ;
buffer - > erase ( iter , end_iter ) ;
}
auto iter = buffer - > end ( ) ;
if ( ! iter . starts_line ( ) )
buffer - > insert ( buffer - > end ( ) , " \n " ) ;
buffer - > end_user_action ( ) ;
}
if ( filesystem : : write ( file_path , get_buffer ( ) ) ) {
last_read_time = std : : chrono : : system_clock : : to_time_t ( std : : chrono : : system_clock : : now ( ) ) ;
get_buffer ( ) - > set_modified ( false ) ;
return true ;
}
else {
Terminal : : get ( ) . print ( " Error: could not save file " + file_path . string ( ) + " \n " , true ) ;
return false ;
}
}
void Source : : View : : configure ( ) {
//TODO: Move this to notebook? Might take up too much memory doing this for every tab.
auto style_scheme_manager = Gsv : : StyleSchemeManager : : get_default ( ) ;
@ -388,6 +449,8 @@ void Source::View::configure() {
Terminal : : get ( ) . print ( " Error: Could not find gtksourceview style: " + Config : : get ( ) . source . style + ' \n ' , true ) ;
}
set_draw_spaces ( parse_show_whitespace_characters ( Config : : get ( ) . source . show_whitespace_characters ) ) ;
if ( Config : : get ( ) . source . wrap_lines )
set_wrap_mode ( Gtk : : WrapMode : : WRAP_CHAR ) ;
else
@ -561,7 +624,7 @@ void Source::View::set_tooltip_and_dialog_events() {
}
void Source : : View : : search_occurrences_updated ( GtkWidget * widget , GParamSpec * property , gpointer data ) {
auto view = ( Source : : View * ) data ;
auto view = static_cast < Source : : View * > ( data ) ;
if ( view - > update_search_occurrences )
view - > update_search_occurrences ( gtk_source_search_context_get_occurrences_count ( view - > search_context ) ) ;
}
@ -700,13 +763,13 @@ void Source::View::paste() {
paste_line = false ;
}
}
if ( paste_line_tabs = = ( size_t ) - 1 )
if ( paste_line_tabs = = static_cast < size_t > ( - 1 ) )
paste_line_tabs = 0 ;
start_line = 0 ;
end_line = 0 ;
paste_line = false ;
first_paste_line = true ;
get_source_ buffer ( ) - > begin_user_action ( ) ;
get_buffer ( ) - > begin_user_action ( ) ;
for ( size_t c = 0 ; c < text . size ( ) ; c + + ) {
if ( text [ c ] = = ' \n ' ) {
end_line = c ;
@ -744,7 +807,7 @@ void Source::View::paste() {
}
}
get_buffer ( ) - > place_cursor ( get_buffer ( ) - > get_insert ( ) - > get_iter ( ) ) ;
get_source_ buffer ( ) - > end_user_action ( ) ;
get_buffer ( ) - > end_user_action ( ) ;
scroll_to_cursor_delayed ( this , false , false ) ;
}
else {
@ -756,19 +819,42 @@ void Source::View::paste() {
Gtk : : TextIter Source : : View : : get_iter_for_dialog ( ) {
auto iter = get_buffer ( ) - > get_insert ( ) - > get_iter ( ) ;
if ( iter . get_line_offset ( ) > = 80 )
iter = get_buffer ( ) - > get_iter_at_line ( iter . get_line ( ) ) ;
Gdk : : Rectangle visible_rect ;
get_visible_rect ( visible_rect ) ;
Gdk : : Rectangle iter_rect ;
get_iter_location ( iter , iter_rect ) ;
iter_rect . set_width ( 1 ) ;
if ( ! visible_rect . intersects ( iter_rect ) ) {
get_iter_at_location ( iter , 0 , visible_rect . get_y ( ) + visible_rect . get_height ( ) / 3 ) ;
if ( iter . get_line_offset ( ) > = 80 ) {
get_iter_at_location ( iter , visible_rect . get_x ( ) , iter_rect . get_y ( ) ) ;
get_iter_location ( iter , iter_rect ) ;
}
if ( ! visible_rect . intersects ( iter_rect ) )
get_iter_at_location ( iter , visible_rect . get_x ( ) , visible_rect . get_y ( ) + visible_rect . get_height ( ) / 3 ) ;
return iter ;
}
void Source : : View : : place_cursor_at_line_offset ( int line , int offset ) {
line = std : : min ( line , get_buffer ( ) - > get_line_count ( ) - 1 ) ;
if ( line < 0 )
line = 0 ;
auto iter = get_buffer ( ) - > get_iter_at_line ( line ) ;
while ( ! iter . ends_line ( ) )
iter . forward_char ( ) ;
offset = std : : min ( offset , iter . get_line_offset ( ) ) ;
get_buffer ( ) - > place_cursor ( get_buffer ( ) - > get_iter_at_line_offset ( line , offset ) ) ;
}
void Source : : View : : place_cursor_at_line_index ( int line , int index ) {
line = std : : min ( line , get_buffer ( ) - > get_line_count ( ) - 1 ) ;
if ( line < 0 )
line = 0 ;
auto iter = get_buffer ( ) - > get_iter_at_line ( line ) ;
while ( ! iter . ends_line ( ) )
iter . forward_char ( ) ;
index = std : : min ( index , iter . get_line_index ( ) ) ;
get_buffer ( ) - > place_cursor ( get_buffer ( ) - > get_iter_at_line_index ( line , index ) ) ;
}
void Source : : View : : set_status ( const std : : string & status ) {
this - > status = status ;
if ( on_update_status )
@ -870,7 +956,7 @@ std::string Source::View::get_line(const Gtk::TextIter &iter) {
auto line_start_it = get_buffer ( ) - > get_iter_at_line ( iter . get_line ( ) ) ;
auto line_end_it = iter ;
while ( ! line_end_it . ends_line ( ) & & line_end_it . forward_char ( ) ) { }
std : : string line ( get_source_ buffer ( ) - > get_text ( line_start_it , line_end_it ) ) ;
std : : string line ( get_buffer ( ) - > get_text ( line_start_it , line_end_it ) ) ;
return line ;
}
std : : string Source : : View : : get_line ( Glib : : RefPtr < Gtk : : TextBuffer : : Mark > mark ) {
@ -884,8 +970,8 @@ std::string Source::View::get_line() {
}
std : : string Source : : View : : get_line_before ( const Gtk : : TextIter & iter ) {
auto line_it = get_source_ buffer ( ) - > get_iter_at_line ( iter . get_line ( ) ) ;
std : : string line ( get_source_ buffer ( ) - > get_text ( line_it , iter ) ) ;
auto line_it = get_buffer ( ) - > get_iter_at_line ( iter . get_line ( ) ) ;
std : : string line ( get_buffer ( ) - > get_text ( line_it , iter ) ) ;
return line ;
}
std : : string Source : : View : : get_line_before ( Glib : : RefPtr < Gtk : : TextBuffer : : Mark > mark ) {
@ -902,7 +988,7 @@ Gtk::TextIter Source::View::get_tabs_end_iter(Glib::RefPtr<Gtk::TextBuffer::Mark
return get_tabs_end_iter ( mark - > get_iter ( ) ) ;
}
Gtk : : TextIter Source : : View : : get_tabs_end_iter ( int line_nr ) {
auto sentence_iter = get_source_ buffer ( ) - > get_iter_at_line ( line_nr ) ;
auto sentence_iter = get_buffer ( ) - > get_iter_at_line ( line_nr ) ;
while ( ( * sentence_iter = = ' ' | | * sentence_iter = = ' \t ' ) & & ! sentence_iter . ends_line ( ) & & sentence_iter . forward_char ( ) ) { }
return sentence_iter ;
}
@ -1045,6 +1131,23 @@ bool Source::View::find_left_bracket_backward(Gtk::TextIter iter, Gtk::TextIter
return false ;
}
std : : string Source : : View : : get_token ( Gtk : : TextIter iter ) {
auto start = iter ;
auto end = iter ;
while ( ( * iter > = ' A ' & & * iter < = ' Z ' ) | | ( * iter > = ' a ' & & * iter < = ' z ' ) | | ( * iter > = ' 0 ' & & * iter < = ' 9 ' ) | | * iter = = ' _ ' ) {
start = iter ;
if ( ! iter . backward_char ( ) )
break ;
}
while ( ( * end > = ' A ' & & * end < = ' Z ' ) | | ( * end > = ' a ' & & * end < = ' z ' ) | | ( * end > = ' 0 ' & & * end < = ' 9 ' ) | | * end = = ' _ ' ) {
if ( ! end . forward_char ( ) )
break ;
}
return get_buffer ( ) - > get_text ( start , end ) ;
}
bool Source : : View : : on_key_press_event ( GdkEventKey * key ) {
if ( spellcheck_suggestions_dialog & & spellcheck_suggestions_dialog - > shown ) {
if ( spellcheck_suggestions_dialog - > on_key_press ( key ) )
@ -1075,7 +1178,7 @@ bool Source::View::on_key_press_event(GdkEventKey* key) {
//Basic indentation
bool Source : : View : : on_key_press_event_basic ( GdkEventKey * key ) {
get_source_ buffer ( ) - > begin_user_action ( ) ;
get_buffer ( ) - > begin_user_action ( ) ;
auto iter = get_buffer ( ) - > get_insert ( ) - > get_iter ( ) ;
//Indent as in next or previous line
if ( key - > keyval = = GDK_KEY_Return & & ! get_buffer ( ) - > get_has_selection ( ) & & ! iter . starts_line ( ) ) {
@ -1103,15 +1206,15 @@ bool Source::View::on_key_press_event_basic(GdkEventKey* key) {
auto next_line_tabs_end_iter = get_tabs_end_iter ( line_nr + 1 ) ;
auto next_line_tabs = get_line_before ( next_line_tabs_end_iter ) ;
if ( iter . ends_line ( ) & & next_line_tabs . size ( ) > line_tabs . size ( ) ) {
get_source_ buffer ( ) - > insert_at_cursor ( " \n " + next_line_tabs ) ;
scroll_to ( get_source_ buffer ( ) - > get_insert ( ) ) ;
get_source_ buffer ( ) - > end_user_action ( ) ;
get_buffer ( ) - > insert_at_cursor ( " \n " + next_line_tabs ) ;
scroll_to ( get_buffer ( ) - > get_insert ( ) ) ;
get_buffer ( ) - > end_user_action ( ) ;
return true ;
}
}
get_source_ buffer ( ) - > insert_at_cursor ( " \n " + line_tabs ) ;
scroll_to ( get_source_ buffer ( ) - > get_insert ( ) ) ;
get_source_ buffer ( ) - > end_user_action ( ) ;
get_buffer ( ) - > insert_at_cursor ( " \n " + line_tabs ) ;
scroll_to ( get_buffer ( ) - > get_insert ( ) ) ;
get_buffer ( ) - > end_user_action ( ) ;
return true ;
}
//Indent right when clicking tab, no matter where in the line the cursor is. Also works on selected text.
@ -1135,34 +1238,34 @@ bool Source::View::on_key_press_event_basic(GdkEventKey* key) {
tabs = next_line_tabs ;
if ( tabs . size ( ) > = tab_size ) {
get_buffer ( ) - > insert_at_cursor ( tabs ) ;
get_source_ buffer ( ) - > end_user_action ( ) ;
get_buffer ( ) - > end_user_action ( ) ;
return true ;
}
}
Gtk : : TextIter selection_start , selection_end ;
get_source_ buffer ( ) - > get_selection_bounds ( selection_start , selection_end ) ;
get_buffer ( ) - > get_selection_bounds ( selection_start , selection_end ) ;
int line_start = selection_start . get_line ( ) ;
int line_end = selection_end . get_line ( ) ;
for ( int line = line_start ; line < = line_end ; line + + ) {
Gtk : : TextIter line_it = get_source_ buffer ( ) - > get_iter_at_line ( line ) ;
Gtk : : TextIter line_it = get_buffer ( ) - > get_iter_at_line ( line ) ;
if ( ! get_buffer ( ) - > get_has_selection ( ) | | line_it ! = selection_end )
get_source_ buffer ( ) - > insert ( line_it , tab ) ;
get_buffer ( ) - > insert ( line_it , tab ) ;
}
get_source_ buffer ( ) - > end_user_action ( ) ;
get_buffer ( ) - > end_user_action ( ) ;
return true ;
}
//Indent left when clicking shift-tab, no matter where in the line the cursor is. Also works on selected text.
else if ( ( key - > keyval = = GDK_KEY_ISO_Left_Tab | | key - > keyval = = GDK_KEY_Tab ) & & ( key - > state & GDK_SHIFT_MASK ) > 0 ) {
Gtk : : TextIter selection_start , selection_end ;
get_source_ buffer ( ) - > get_selection_bounds ( selection_start , selection_end ) ;
get_buffer ( ) - > get_selection_bounds ( selection_start , selection_end ) ;
int line_start = selection_start . get_line ( ) ;
int line_end = selection_end . get_line ( ) ;
unsigned indent_left_steps = tab_size ;
std : : vector < bool > ignore_line ;
for ( int line_nr = line_start ; line_nr < = line_end ; line_nr + + ) {
auto line_it = get_source_ buffer ( ) - > get_iter_at_line ( line_nr ) ;
auto line_it = get_buffer ( ) - > get_iter_at_line ( line_nr ) ;
if ( ! get_buffer ( ) - > get_has_selection ( ) | | line_it ! = selection_end ) {
auto tabs_end_iter = get_tabs_end_iter ( line_nr ) ;
if ( tabs_end_iter . starts_line ( ) & & tabs_end_iter . ends_line ( ) )
@ -1175,7 +1278,7 @@ bool Source::View::on_key_press_event_basic(GdkEventKey* key) {
ignore_line . push_back ( false ) ;
}
else {
get_source_ buffer ( ) - > end_user_action ( ) ;
get_buffer ( ) - > end_user_action ( ) ;
return true ;
}
}
@ -1183,15 +1286,15 @@ bool Source::View::on_key_press_event_basic(GdkEventKey* key) {
}
for ( int line_nr = line_start ; line_nr < = line_end ; line_nr + + ) {
Gtk : : TextIter line_it = get_source_ buffer ( ) - > get_iter_at_line ( line_nr ) ;
Gtk : : TextIter line_it = get_buffer ( ) - > get_iter_at_line ( line_nr ) ;
Gtk : : TextIter line_plus_it = line_it ;
if ( ! get_buffer ( ) - > get_has_selection ( ) | | line_it ! = selection_end ) {
line_plus_it . forward_chars ( indent_left_steps ) ;
if ( ! ignore_line . at ( line_nr - line_start ) )
get_source_ buffer ( ) - > erase ( line_it , line_plus_it ) ;
get_buffer ( ) - > erase ( line_it , line_plus_it ) ;
}
}
get_source_ buffer ( ) - > end_user_action ( ) ;
get_buffer ( ) - > end_user_action ( ) ;
return true ;
}
//"Smart" backspace key
@ -1256,7 +1359,7 @@ bool Source::View::on_key_press_event_basic(GdkEventKey* key) {
get_buffer ( ) - > place_cursor ( end_line_iter ) ;
}
scroll_to ( get_buffer ( ) - > get_insert ( ) ) ;
get_source_ buffer ( ) - > end_user_action ( ) ;
get_buffer ( ) - > end_user_action ( ) ;
return true ;
}
else if ( key - > keyval = = GDK_KEY_Home & & ( key - > state & GDK_CONTROL_MASK ) = = 0 ) {
@ -1279,7 +1382,7 @@ bool Source::View::on_key_press_event_basic(GdkEventKey* key) {
get_buffer ( ) - > place_cursor ( start_line_iter ) ;
}
scroll_to ( get_buffer ( ) - > get_insert ( ) ) ;
get_source_ buffer ( ) - > end_user_action ( ) ;
get_buffer ( ) - > end_user_action ( ) ;
return true ;
}
@ -1296,7 +1399,8 @@ bool Source::View::on_key_press_event_basic(GdkEventKey* key) {
get_buffer ( ) - > erase ( selection_start , selection_end ) ;
}
get_buffer ( ) - > insert_at_cursor ( Glib : : ustring ( 1 , unicode ) ) ;
get_source_buffer ( ) - > end_user_action ( ) ;
get_buffer ( ) - > end_user_action ( ) ;
scroll_to ( get_buffer ( ) - > get_insert ( ) ) ;
//Trick to make the cursor visible right after insertion:
set_cursor_visible ( false ) ;
@ -1306,13 +1410,13 @@ bool Source::View::on_key_press_event_basic(GdkEventKey* key) {
}
auto stop = Gsv : : View : : on_key_press_event ( key ) ;
get_source_ buffer ( ) - > end_user_action ( ) ;
get_buffer ( ) - > end_user_action ( ) ;
return stop ;
}
//Bracket language indentation
bool Source : : View : : on_key_press_event_bracket_language ( GdkEventKey * key ) {
get_source_ buffer ( ) - > begin_user_action ( ) ;
get_buffer ( ) - > begin_user_action ( ) ;
auto iter = get_buffer ( ) - > get_insert ( ) - > get_iter ( ) ;
//Indent depending on if/else/etc and brackets
if ( key - > keyval = = GDK_KEY_Return & & ! iter . starts_line ( ) ) {
@ -1337,7 +1441,7 @@ bool Source::View::on_key_press_event_bracket_language(GdkEventKey* key) {
auto start_sentence_tabs_end_iter = get_tabs_end_iter ( start_of_sentence_iter ) ;
auto tabs = get_line_before ( start_sentence_tabs_end_iter ) ;
boost : : smatch sm ;
REGEX_NS : : smatch sm ;
if ( iter . backward_char ( ) & & * iter = = ' { ' ) {
auto found_iter = iter ;
bool found_right_bracket = find_right_bracket_forward ( iter , found_iter ) ;
@ -1350,30 +1454,43 @@ bool Source::View::on_key_press_event_bracket_language(GdkEventKey* key) {
has_bracket = true ;
}
if ( * get_buffer ( ) - > get_insert ( ) - > get_iter ( ) = = ' } ' ) {
get_source_ buffer ( ) - > insert_at_cursor ( " \n " + tabs + tab + " \n " + tabs ) ;
auto insert_it = get_source_ buffer ( ) - > get_insert ( ) - > get_iter ( ) ;
get_buffer ( ) - > insert_at_cursor ( " \n " + tabs + tab + " \n " + tabs ) ;
auto insert_it = get_buffer ( ) - > get_insert ( ) - > get_iter ( ) ;
if ( insert_it . backward_chars ( tabs . size ( ) + 1 ) ) {
scroll_to ( get_source_ buffer ( ) - > get_insert ( ) ) ;
get_source_ buffer ( ) - > place_cursor ( insert_it ) ;
scroll_to ( get_buffer ( ) - > get_insert ( ) ) ;
get_buffer ( ) - > place_cursor ( insert_it ) ;
}
get_source_ buffer ( ) - > end_user_action ( ) ;
get_buffer ( ) - > end_user_action ( ) ;
return true ;
}
else if ( ! has_bracket ) {
//Insert new lines with bracket end
get_source_buffer ( ) - > insert_at_cursor ( " \n " + tabs + tab + " \n " + tabs + " } " ) ;
auto insert_it = get_source_buffer ( ) - > get_insert ( ) - > get_iter ( ) ;
if ( insert_it . backward_chars ( tabs . size ( ) + 2 ) ) {
scroll_to ( get_source_buffer ( ) - > get_insert ( ) ) ;
get_source_buffer ( ) - > place_cursor ( insert_it ) ;
bool add_semicolon = false ;
if ( language & & ( language - > get_id ( ) = = " chdr " | | language - > get_id ( ) = = " cpphdr " | |
language - > get_id ( ) = = " c " | | language - > get_id ( ) = = " cpp " ) ) {
auto token = get_token ( start_of_sentence_iter ) ;
if ( token . empty ( ) ) {
auto iter = start_of_sentence_iter ;
while ( ! iter . starts_line ( ) & & iter . backward_char ( ) ) { }
if ( iter . backward_char ( ) & & find_start_of_closed_expression ( iter , iter ) )
token = get_token ( iter ) ;
}
if ( token = = " class " | | token = = " struct " )
add_semicolon = true ;
}
get_buffer ( ) - > insert_at_cursor ( " \n " + tabs + tab + " \n " + tabs + ( add_semicolon ? " }; " : " } " ) ) ;
auto insert_it = get_buffer ( ) - > get_insert ( ) - > get_iter ( ) ;
if ( insert_it . backward_chars ( tabs . size ( ) + ( add_semicolon ? 3 : 2 ) ) ) {
scroll_to ( get_buffer ( ) - > get_insert ( ) ) ;
get_buffer ( ) - > place_cursor ( insert_it ) ;
}
get_source_buffer ( ) - > end_user_action ( ) ;
get_buffer ( ) - > end_user_action ( ) ;
return true ;
}
else {
get_source_buffer ( ) - > insert_at_cursor ( " \n " + tabs + tab ) ;
get_buffer ( ) - > insert_at_cursor ( " \n " + tabs + tab ) ;
scroll_to ( get_buffer ( ) - > get_insert ( ) ) ;
get_source_buffer ( ) - > end_user_action ( ) ;
get_buffer ( ) - > end_user_action ( ) ;
return true ;
}
}
@ -1389,35 +1506,35 @@ bool Source::View::on_key_press_event_bracket_language(GdkEventKey* key) {
iter . forward_char ( ) ;
}
}
else if ( boost : : regex_match ( line , sm , no_bracket_statement_regex ) ) {
get_source_ buffer ( ) - > insert_at_cursor ( " \n " + tabs + tab ) ;
scroll_to ( get_source_ buffer ( ) - > get_insert ( ) ) ;
get_source_ buffer ( ) - > end_user_action ( ) ;
else if ( REGEX_NS : : regex_match ( line , sm , no_bracket_statement_regex ) ) {
get_buffer ( ) - > insert_at_cursor ( " \n " + tabs + tab ) ;
scroll_to ( get_buffer ( ) - > get_insert ( ) ) ;
get_buffer ( ) - > end_user_action ( ) ;
return true ;
}
else if ( boost : : regex_match ( line , sm , no_bracket_no_para_statement_regex ) ) {
get_source_ buffer ( ) - > insert_at_cursor ( " \n " + tabs + tab ) ;
scroll_to ( get_source_ buffer ( ) - > get_insert ( ) ) ;
get_source_ buffer ( ) - > end_user_action ( ) ;
else if ( REGEX_NS : : regex_match ( line , sm , no_bracket_no_para_statement_regex ) ) {
get_buffer ( ) - > insert_at_cursor ( " \n " + tabs + tab ) ;
scroll_to ( get_buffer ( ) - > get_insert ( ) ) ;
get_buffer ( ) - > end_user_action ( ) ;
return true ;
}
//Indenting after for instance if(...)\n...;\n
else if ( iter . backward_char ( ) & & * iter = = ' ; ' ) {
boost : : smatch sm2 ;
size_t line_nr = get_source_ buffer ( ) - > get_insert ( ) - > get_iter ( ) . get_line ( ) ;
REGEX_NS : : smatch sm2 ;
size_t line_nr = get_buffer ( ) - > get_insert ( ) - > get_iter ( ) . get_line ( ) ;
if ( line_nr > 0 & & tabs . size ( ) > = tab_size ) {
std : : string previous_line = get_line ( line_nr - 1 ) ;
if ( ! boost : : regex_match ( previous_line , sm2 , bracket_regex ) ) {
if ( boost : : regex_match ( previous_line , sm2 , no_bracket_statement_regex ) ) {
get_source_ buffer ( ) - > insert_at_cursor ( " \n " + sm2 [ 1 ] . str ( ) ) ;
scroll_to ( get_source_ buffer ( ) - > get_insert ( ) ) ;
get_source_ buffer ( ) - > end_user_action ( ) ;
if ( ! REGEX_NS : : regex_match ( previous_line , sm2 , bracket_regex ) ) {
if ( REGEX_NS : : regex_match ( previous_line , sm2 , no_bracket_statement_regex ) ) {
get_buffer ( ) - > insert_at_cursor ( " \n " + sm2 [ 1 ] . str ( ) ) ;
scroll_to ( get_buffer ( ) - > get_insert ( ) ) ;
get_buffer ( ) - > end_user_action ( ) ;
return true ;
}
else if ( boost : : regex_match ( previous_line , sm2 , no_bracket_no_para_statement_regex ) ) {
get_source_ buffer ( ) - > insert_at_cursor ( " \n " + sm2 [ 1 ] . str ( ) ) ;
scroll_to ( get_source_ buffer ( ) - > get_insert ( ) ) ;
get_source_ buffer ( ) - > end_user_action ( ) ;
else if ( REGEX_NS : : regex_match ( previous_line , sm2 , no_bracket_no_para_statement_regex ) ) {
get_buffer ( ) - > insert_at_cursor ( " \n " + sm2 [ 1 ] . str ( ) ) ;
scroll_to ( get_buffer ( ) - > get_insert ( ) ) ;
get_buffer ( ) - > end_user_action ( ) ;
return true ;
}
}
@ -1431,7 +1548,7 @@ bool Source::View::on_key_press_event_bracket_language(GdkEventKey* key) {
left_bracket_iter . forward_char ( ) ;
Gtk : : TextIter start_of_left_bracket_sentence_iter ;
if ( find_start_of_closed_expression ( left_bracket_iter , start_of_left_bracket_sentence_iter ) ) {
boost : : smatch sm ;
REGEX_NS : : smatch sm ;
auto tabs_end_iter = get_tabs_end_iter ( start_of_left_bracket_sentence_iter ) ;
auto tabs_start_of_sentence = get_line_before ( tabs_end_iter ) ;
if ( tabs . size ( ) = = ( tabs_start_of_sentence . size ( ) + tab_size ) ) {
@ -1442,17 +1559,17 @@ bool Source::View::on_key_press_event_bracket_language(GdkEventKey* key) {
get_buffer ( ) - > erase ( start_line_iter , start_line_plus_tab_size ) ;
}
else {
get_source_ buffer ( ) - > insert_at_cursor ( " \n " + tabs + tab ) ;
scroll_to ( get_source_ buffer ( ) - > get_insert ( ) ) ;
get_source_ buffer ( ) - > end_user_action ( ) ;
get_buffer ( ) - > insert_at_cursor ( " \n " + tabs + tab ) ;
scroll_to ( get_buffer ( ) - > get_insert ( ) ) ;
get_buffer ( ) - > end_user_action ( ) ;
return true ;
}
}
}
}
get_source_ buffer ( ) - > insert_at_cursor ( " \n " + tabs ) ;
scroll_to ( get_source_ buffer ( ) - > get_insert ( ) ) ;
get_source_ buffer ( ) - > end_user_action ( ) ;
get_buffer ( ) - > insert_at_cursor ( " \n " + tabs ) ;
scroll_to ( get_buffer ( ) - > get_insert ( ) ) ;
get_buffer ( ) - > end_user_action ( ) ;
return true ;
}
}
@ -1462,19 +1579,19 @@ bool Source::View::on_key_press_event_bracket_language(GdkEventKey* key) {
if ( line . size ( ) > = tab_size ) {
for ( auto c : line ) {
if ( c ! = tab_char ) {
get_source_ buffer ( ) - > insert_at_cursor ( " } " ) ;
get_source_ buffer ( ) - > end_user_action ( ) ;
get_buffer ( ) - > insert_at_cursor ( " } " ) ;
get_buffer ( ) - > end_user_action ( ) ;
return true ;
}
}
Gtk : : TextIter insert_it = get_source_ buffer ( ) - > get_insert ( ) - > get_iter ( ) ;
Gtk : : TextIter line_it = get_source_ buffer ( ) - > get_iter_at_line ( insert_it . get_line ( ) ) ;
Gtk : : TextIter insert_it = get_buffer ( ) - > get_insert ( ) - > get_iter ( ) ;
Gtk : : TextIter line_it = get_buffer ( ) - > get_iter_at_line ( insert_it . get_line ( ) ) ;
Gtk : : TextIter line_plus_it = line_it ;
line_plus_it . forward_chars ( tab_size ) ;
get_source_ buffer ( ) - > erase ( line_it , line_plus_it ) ;
get_buffer ( ) - > erase ( line_it , line_plus_it ) ;
}
get_source_ buffer ( ) - > insert_at_cursor ( " } " ) ;
get_source_ buffer ( ) - > end_user_action ( ) ;
get_buffer ( ) - > insert_at_cursor ( " } " ) ;
get_buffer ( ) - > end_user_action ( ) ;
return true ;
}
//Indent left when writing { on a new line after for instance if(...)\n...
@ -1485,12 +1602,12 @@ bool Source::View::on_key_press_event_bracket_language(GdkEventKey* key) {
size_t line_nr = iter . get_line ( ) ;
if ( line_nr > 0 & & tabs . size ( ) > = tab_size & & iter = = tabs_end_iter ) {
std : : string previous_line = get_line ( line_nr - 1 ) ;
boost : : smatch sm ;
if ( ! boost : : regex_match ( previous_line , sm , bracket_regex ) ) {
REGEX_NS : : smatch sm ;
if ( ! REGEX_NS : : regex_match ( previous_line , sm , bracket_regex ) ) {
auto start_iter = iter ;
start_iter . backward_chars ( tab_size ) ;
if ( boost : : regex_match ( previous_line , sm , no_bracket_statement_regex ) | |
boost : : regex_match ( previous_line , sm , no_bracket_no_para_statement_regex ) ) {
if ( REGEX_NS : : regex_match ( previous_line , sm , no_bracket_statement_regex ) | |
REGEX_NS : : regex_match ( previous_line , sm , no_bracket_no_para_statement_regex ) ) {
if ( ( tabs . size ( ) - tab_size ) = = sm [ 1 ] . str ( ) . size ( ) ) {
get_buffer ( ) - > erase ( start_iter , iter ) ;
get_buffer ( ) - > insert_at_cursor ( " { " ) ;
@ -1503,7 +1620,7 @@ bool Source::View::on_key_press_event_bracket_language(GdkEventKey* key) {
}
}
get_source_ buffer ( ) - > end_user_action ( ) ;
get_buffer ( ) - > end_user_action ( ) ;
return on_key_press_event_basic ( key ) ;
}
@ -1528,6 +1645,14 @@ bool Source::View::on_button_press_event(GdkEventButton *event) {
return Gsv : : View : : on_button_press_event ( event ) ;
}
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 ( " Caution: " + file_path . filename ( ) . string ( ) + " was altered outside of juCi++ " ) ;
return Gsv : : View : : on_focus_in_event ( focus_event ) ;
} ;
std : : pair < char , unsigned > Source : : View : : find_tab_char_and_size ( ) {
std : : unordered_map < char , size_t > tab_chars ;
std : : unordered_map < unsigned , size_t > tab_sizes ;
@ -1682,7 +1807,7 @@ std::pair<char, unsigned> Source::View::find_tab_char_and_size() {
}
bool Source : : View : : is_word_iter ( const Gtk : : TextIter & iter ) {
return ( ( * iter > = 65 & & * iter < = 90 ) | | ( * iter > = 97 & & * iter < = 122 ) | | * iter = = 39 | | * iter > = 128 ) ;
return ( ( * iter > = ' A ' & & * iter < = ' Z ' ) | | ( * iter > = ' a ' & & * iter < = ' z ' ) | | * iter = = ' \' ' | | * iter > = 128 ) ;
}
std : : pair < Gtk : : TextIter , Gtk : : TextIter > Source : : View : : spellcheck_get_word ( Gtk : : TextIter iter ) {