@ -2,6 +2,7 @@
# include "config.hpp"
# include "config.hpp"
# include "project_build.hpp"
# include "project_build.hpp"
# include "terminal.hpp"
# include "terminal.hpp"
# include <future>
# ifdef JUCI_ENABLE_DEBUG
# ifdef JUCI_ENABLE_DEBUG
# include "debug_lldb.hpp"
# include "debug_lldb.hpp"
# endif
# endif
@ -92,10 +93,7 @@ void Source::ClangViewParse::configure() {
void Source : : ClangViewParse : : parse_initialize ( ) {
void Source : : ClangViewParse : : parse_initialize ( ) {
hide_tooltips ( ) ;
hide_tooltips ( ) ;
parsed = false ;
parsed = false ;
if ( parse_thread . joinable ( ) )
parse_thread . join ( ) ;
parse_state = ParseState : : processing ;
parse_state = ParseState : : processing ;
parse_process_state = ParseProcessState : : starting ;
auto buffer_ = get_buffer ( ) - > get_text ( ) ;
auto buffer_ = get_buffer ( ) - > get_text ( ) ;
auto & buffer_raw = const_cast < std : : string & > ( buffer_ . raw ( ) ) ;
auto & buffer_raw = const_cast < std : : string & > ( buffer_ . raw ( ) ) ;
@ -140,33 +138,33 @@ void Source::ClangViewParse::parse_initialize() {
status_state = " parsing... " ;
status_state = " parsing... " ;
if ( update_status_state )
if ( update_status_state )
update_status_state ( this ) ;
update_status_state ( this ) ;
parse_thread = std : : thread ( [ this ] ( ) {
size_t count = + + parse_count ;
while ( true ) {
dispatcher . post ( [ this , count ] { // Do not run in constructor to avoid data race on vptr (detected by thread sanitizer)
while ( parse_state = = ParseState : : processing & & parse_process_state ! = ParseProcessState : : starting & & parse_process_state ! = ParseProcessState : : processing )
if ( count = = parse_count )
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 10 ) ) ;
parse ( count ) ;
} ) ;
}
void Source : : ClangViewParse : : parse ( size_t count ) {
if ( parse_state ! = ParseState : : processing )
if ( parse_state ! = ParseState : : processing )
break ;
return ;
auto expected = ParseProcessState : : starting ;
if ( parse_process_state . compare_exchange_strong ( expected , ParseProcessState : : preprocessing ) ) {
dispatcher . post ( [ this ] {
auto expected = ParseProcessState : : preprocessing ;
if ( parse_mutex . try_lock ( ) ) {
if ( parse_mutex . try_lock ( ) ) {
if ( parse_process_state . compare_exchange_strong ( expected , ParseProcessState : : processing ) )
parse_thread_buffer = get_buffer ( ) - > get_text ( ) ;
parse_thread_buffer = get_buffer ( ) - > get_text ( ) ;
parse_mutex . unlock ( ) ;
parse_mutex . unlock ( ) ;
}
else
worker . post ( [ this , count ] {
parse_process_state . compare_exchange_strong ( expected , ParseProcessState : : starting ) ;
if ( count ! = parse_count | | parse_state ! = ParseState : : processing )
} ) ;
return ;
}
if ( parse_mutex . try_lock ( ) ) {
else if ( parse_process_state = = ParseProcessState : : processing & & parse_mutex . try_lock ( ) ) {
auto & parse_thread_buffer_raw = const_cast < std : : string & > ( parse_thread_buffer . raw ( ) ) ;
auto & parse_thread_buffer_raw = const_cast < std : : string & > ( parse_thread_buffer . raw ( ) ) ;
if ( is_language ( { " chdr " , " cpphdr " } ) )
if ( is_language ( { " chdr " , " cpphdr " } ) )
clangmm : : remove_include_guard ( parse_thread_buffer_raw ) ;
clangmm : : remove_include_guard ( parse_thread_buffer_raw ) ;
auto status = clang_tu - > reparse ( parse_thread_buffer_raw ) ;
auto status = clang_tu - > reparse ( parse_thread_buffer_raw ) ;
if ( status = = 0 ) {
if ( status = = 0 ) {
auto expected = ParseProcessState : : processing ;
if ( count ! = parse_count | | parse_state ! = ParseState : : processing ) {
if ( parse_process_state . compare_exchange_strong ( expected , ParseProcessState : : postprocessing ) ) {
parse_mutex . unlock ( ) ;
return ;
}
clang_tokens = clang_tu - > get_tokens ( ) ;
clang_tokens = clang_tu - > get_tokens ( ) ;
clang_tokens_offsets . clear ( ) ;
clang_tokens_offsets . clear ( ) ;
clang_tokens_offsets . reserve ( clang_tokens - > size ( ) ) ;
clang_tokens_offsets . reserve ( clang_tokens - > size ( ) ) ;
@ -174,26 +172,22 @@ void Source::ClangViewParse::parse_initialize() {
clang_tokens_offsets . emplace_back ( token . get_source_range ( ) . get_offsets ( ) ) ;
clang_tokens_offsets . emplace_back ( token . get_source_range ( ) . get_offsets ( ) ) ;
clang_diagnostics = clang_tu - > get_diagnostics ( ) ;
clang_diagnostics = clang_tu - > get_diagnostics ( ) ;
parse_mutex . unlock ( ) ;
parse_mutex . unlock ( ) ;
dispatcher . post ( [ this ] {
dispatcher . post ( [ this , count ] {
if ( count ! = parse_count | | parse_state ! = ParseState : : processing )
return ;
if ( parse_mutex . try_lock ( ) ) {
if ( parse_mutex . try_lock ( ) ) {
auto expected = ParseProcessState : : postprocessing ;
if ( parse_process_state . compare_exchange_strong ( expected , ParseProcessState : : idle ) ) {
update_syntax ( ) ;
update_syntax ( ) ;
update_diagnostics ( ) ;
update_diagnostics ( ) ;
parsed = true ;
parsed = true ;
status_state = " " ;
status_state = " " ;
if ( update_status_state )
if ( update_status_state )
update_status_state ( this ) ;
update_status_state ( this ) ;
}
parse_mutex . unlock ( ) ;
parse_mutex . unlock ( ) ;
}
}
} ) ;
} ) ;
}
}
else
parse_mutex . unlock ( ) ;
}
else {
else {
parse_state = ParseState : : stop ;
parse_state = ParseState : : stopped ;
parse_mutex . unlock ( ) ;
parse_mutex . unlock ( ) ;
dispatcher . post ( [ this ] {
dispatcher . post ( [ this ] {
Terminal : : get ( ) . print ( " \ e[31mError \ e[m: failed to reparse " + filesystem : : get_short_path ( this - > file_path ) . string ( ) + " \n " , true ) ;
Terminal : : get ( ) . print ( " \ e[31mError \ e[m: failed to reparse " + filesystem : : get_short_path ( this - > file_path ) . string ( ) + " \n " , true ) ;
@ -206,9 +200,20 @@ void Source::ClangViewParse::parse_initialize() {
} ) ;
} ) ;
}
}
}
}
}
} ) ;
} ) ;
}
}
else {
delayed_reparse_connection . disconnect ( ) ;
size_t count = + + parse_count ;
delayed_reparse_connection = Glib : : signal_timeout ( ) . connect (
[ this , count ] {
if ( count = = parse_count )
parse ( count ) ;
return false ;
} ,
100 ) ;
}
}
void Source : : ClangViewParse : : soft_reparse ( bool delayed ) {
void Source : : ClangViewParse : : soft_reparse ( bool delayed ) {
soft_reparse_needed = false ;
soft_reparse_needed = false ;
@ -218,16 +223,15 @@ void Source::ClangViewParse::soft_reparse(bool delayed) {
if ( parse_state ! = ParseState : : processing )
if ( parse_state ! = ParseState : : processing )
return ;
return ;
parse_process_state = ParseProcessState : : idle ;
size_t count = + + parse_count ;
auto reparse = [ this , count ] {
auto reparse = [ this ] {
parsed = false ;
parsed = false ;
auto expected = ParseProcessState : : idle ;
if ( count ! = parse_count )
if ( parse_process_state . compare_exchange_strong ( expected , ParseProcessState : : starting ) ) {
return false ;
status_state = " parsing... " ;
status_state = " parsing... " ;
if ( update_status_state )
if ( update_status_state )
update_status_state ( this ) ;
update_status_state ( this ) ;
}
parse ( count ) ;
return false ;
return false ;
} ;
} ;
if ( delayed )
if ( delayed )
@ -837,7 +841,7 @@ Source::ClangViewAutocomplete::ClangViewAutocomplete(const boost::filesystem::pa
} ;
} ;
autocomplete . stop_parse = [ this ] ( ) {
autocomplete . stop_parse = [ this ] ( ) {
parse_process_state = ParseProcessState : : idle ;
+ + parse_count ;
} ;
} ;
// Activate argument completions
// Activate argument completions
@ -2043,7 +2047,7 @@ bool Source::ClangViewRefactor::wait_parsing() {
while ( true ) {
while ( true ) {
size_t not_parsed = 0 ;
size_t not_parsed = 0 ;
for ( auto & clang_view : not_parsed_clang_views ) {
for ( auto & clang_view : not_parsed_clang_views ) {
if ( clang_view - > parse_state = = ParseState : : stop ) {
if ( clang_view - > parse_state = = ParseState : : stopped ) {
Info : : get ( ) . print ( " Canceled due to parsing error in " + clang_view - > file_path . string ( ) ) ;
Info : : get ( ) . print ( " Canceled due to parsing error in " + clang_view - > file_path . string ( ) ) ;
return false ;
return false ;
}
}
@ -2126,6 +2130,8 @@ void Source::ClangView::full_reparse() {
if ( parse_state ! = ParseState : : processing )
if ( parse_state ! = ParseState : : processing )
return ;
return ;
+ + parse_count ;
if ( full_reparse_running ) {
if ( full_reparse_running ) {
delayed_full_reparse_connection = Glib : : signal_timeout ( ) . connect (
delayed_full_reparse_connection = Glib : : signal_timeout ( ) . connect (
[ this ] {
[ this ] {
@ -2137,19 +2143,17 @@ void Source::ClangView::full_reparse() {
}
}
full_reparse_needed = false ;
full_reparse_needed = false ;
parse_process_state = ParseProcessState : : idle ;
autocomplete . state = Autocomplete : : State : : idle ;
autocomplete . state = Autocomplete : : State : : idle ;
auto expected = ParseState : : processing ;
auto expected = ParseState : : processing ;
if ( ! parse_state . compare_exchange_strong ( expected , ParseState : : restarting ) )
if ( ! parse_state . compare_exchange_strong ( expected , ParseState : : idle ) )
return ;
return ;
full_reparse_running = true ;
full_reparse_running = true ;
if ( full_reparse_thread . joinable ( ) )
if ( full_reparse_thread . joinable ( ) )
full_reparse_thread . join ( ) ;
full_reparse_thread . join ( ) ;
full_reparse_thread = std : : thread ( [ this ] ( ) {
full_reparse_thread = std : : thread ( [ this ] ( ) {
if ( parse_thread . joinable ( ) )
+ + parse_count ;
parse_thread . join ( ) ;
worker . restart ( ) ;
if ( autocomplete . thread . joinable ( ) )
if ( autocomplete . thread . joinable ( ) )
autocomplete . thread . join ( ) ;
autocomplete . thread . join ( ) ;
dispatcher . post ( [ this ] {
dispatcher . post ( [ this ] {
@ -2175,6 +2179,7 @@ void Source::ClangView::async_delete() {
Usages : : Clang : : cache_in_progress ( ) ;
Usages : : Clang : : cache_in_progress ( ) ;
delayed_reparse_connection . disconnect ( ) ;
delayed_reparse_connection . disconnect ( ) ;
delayed_full_reparse_connection . disconnect ( ) ;
if ( full_reparse_needed )
if ( full_reparse_needed )
full_reparse ( ) ;
full_reparse ( ) ;
else if ( soft_reparse_needed | | ! parsed )
else if ( soft_reparse_needed | | ! parsed )
@ -2182,9 +2187,9 @@ void Source::ClangView::async_delete() {
auto before_parse_time = std : : time ( nullptr ) ;
auto before_parse_time = std : : time ( nullptr ) ;
delete_thread = std : : thread ( [ this , before_parse_time , project_paths_in_use = std : : move ( project_paths_in_use ) , buffer_modified = get_buffer ( ) - > get_modified ( ) ] {
delete_thread = std : : thread ( [ this , before_parse_time , project_paths_in_use = std : : move ( project_paths_in_use ) , buffer_modified = get_buffer ( ) - > get_modified ( ) ] {
while ( ! parsed & & parse_state ! = ParseState : : stop )
while ( ! parsed & & parse_state ! = ParseState : : stopped )
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 10 ) ) ;
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 10 ) ) ;
parse_state = ParseState : : stop ;
parse_state = ParseState : : stopped ;
if ( buffer_modified ) {
if ( buffer_modified ) {
std : : ifstream stream ( file_path . string ( ) , std : : ios : : binary ) ;
std : : ifstream stream ( file_path . string ( ) , std : : ios : : binary ) ;
@ -2209,8 +2214,8 @@ void Source::ClangView::async_delete() {
if ( full_reparse_thread . joinable ( ) )
if ( full_reparse_thread . joinable ( ) )
full_reparse_thread . join ( ) ;
full_reparse_thread . join ( ) ;
if ( parse_thread . joinable ( ) )
+ + parse_count ;
parse_thread . join ( ) ;
worker . stop ( ) ;
if ( autocomplete . thread . joinable ( ) )
if ( autocomplete . thread . joinable ( ) )
autocomplete . thread . join ( ) ;
autocomplete . thread . join ( ) ;
do_delete_object ( ) ;
do_delete_object ( ) ;