Browse Source

Clang parse cleanup, at least somewhat more understandable now. Also more robust.

merge-requests/365/head
eidheim 10 years ago
parent
commit
7b78a6aea9
  1. 126
      src/source_clang.cc
  2. 26
      src/source_clang.h

126
src/source_clang.cc

@ -21,7 +21,7 @@ namespace sigc {
clang::Index Source::ClangViewParse::clang_index(0, 0);
Source::ClangViewParse::ClangViewParse(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path, Glib::RefPtr<Gsv::Language> language):
Source::View(file_path, project_path, language), parse_error(false) {
Source::View(file_path, project_path, language) {
JDEBUG("start");
auto tag_table=get_buffer()->get_tag_table();
@ -35,36 +35,35 @@ Source::View(file_path, project_path, language), parse_error(false) {
parsing_in_progress=Singleton::terminal->print_in_progress("Parsing "+file_path.string());
//GTK-calls must happen in main thread, so the parse_thread
//sends signals to the main thread that it is to call the following functions:
parse_start_connection=parse_start.connect([this]{
if(parse_thread_buffer_mutex.try_lock()) {
parse_thread_buffer=get_buffer()->get_text();
parse_thread_mapped=true;
parse_thread_buffer_mutex.unlock();
parse_start_connection=parse_preprocess.connect([this]{
auto expected=ParseProcessState::PREPROCESSING;
if(parse_mutex.try_lock()) {
if(parse_process_state.compare_exchange_strong(expected, ParseProcessState::PROCESSING))
parse_thread_buffer=get_buffer()->get_text();
parse_mutex.unlock();
}
parse_thread_go=true;
else
parse_process_state.compare_exchange_strong(expected, ParseProcessState::STARTING);
});
parse_done_connection=parse_done.connect([this](){
if(parse_thread_mapped) {
if(parsing_mutex.try_lock()) {
parse_done_connection=parse_postprocess.connect([this](){
if(parse_mutex.try_lock()) {
auto expected=ParseProcessState::POSTPROCESSING;
if(parse_process_state.compare_exchange_strong(expected, ParseProcessState::IDLE)) {
update_syntax();
update_diagnostics();
parsed=true;
set_status("");
parsing_mutex.unlock();
}
parsing_in_progress->done("done");
}
else {
parse_thread_go=true;
parse_mutex.unlock();
}
});
parse_fail_connection=parse_fail.connect([this](){
parse_fail_connection=parse_error.connect([this](){
Singleton::terminal->print("Error: failed to reparse "+this->file_path.string()+".\n", true);
set_status("");
set_info("");
parsing_in_progress->cancel("failed");
});
init_parse();
parse_initialize();
get_buffer()->signal_changed().connect([this]() {
soft_reparse();
@ -105,13 +104,14 @@ void Source::ClangViewParse::configure() {
no_bracket_no_para_statement_regex=boost::regex("^([ \\t]*)(else|try|do) *$");
}
void Source::ClangViewParse::init_parse() {
void Source::ClangViewParse::parse_initialize() {
type_tooltips.hide();
diagnostic_tooltips.hide();
parsed=false;
parse_thread_go=true;
parse_thread_mapped=false;
parse_thread_stop=false;
if(parse_thread.joinable())
parse_thread.join();
parse_process_state=ParseProcessState::STARTING;
parse_state=ParseState::WORKING;
auto buffer=get_buffer()->get_text();
//Remove includes for first parse for initial syntax highlighting
@ -131,46 +131,53 @@ void Source::ClangViewParse::init_parse() {
update_syntax();
set_status("parsing...");
if(parse_thread.joinable())
parse_thread.join();
parse_thread=std::thread([this]() {
while(true) {
while(!parse_thread_go && !parse_thread_stop)
while(parse_state==ParseState::WORKING && (parse_process_state==ParseProcessState::IDLE || parse_process_state==ParseProcessState::PREPROCESSING || parse_process_state==ParseProcessState::POSTPROCESSING))
std::this_thread::sleep_for(std::chrono::milliseconds(10));
if(parse_thread_stop)
if(parse_state!=ParseState::WORKING)
break;
if(!parse_thread_mapped) {
parse_thread_go=false;
parse_start();
}
else if (parse_thread_mapped && parsing_mutex.try_lock() && parse_thread_buffer_mutex.try_lock()) {
auto status=clang_tu->ReparseTranslationUnit(parse_thread_buffer.raw());
if(status==0)
clang_tokens=clang_tu->get_tokens(0, parse_thread_buffer.bytes()-1);
else
parse_error=true;
parse_thread_go=false;
parsing_mutex.unlock();
parse_thread_buffer_mutex.unlock();
if(status!=0) {
parse_fail();
parse_thread_stop=true;
auto expected=ParseProcessState::STARTING;
if(parse_process_state.compare_exchange_strong(expected, ParseProcessState::PREPROCESSING))
parse_preprocess();
else if (parse_process_state==ParseProcessState::PROCESSING && parse_mutex.try_lock()) {
if(parse_process_state==ParseProcessState::PROCESSING) {
auto status=clang_tu->ReparseTranslationUnit(parse_thread_buffer.raw());
parsing_in_progress->done("done");
if(status==0) {
auto expected=ParseProcessState::PROCESSING;
if(parse_process_state.compare_exchange_strong(expected, ParseProcessState::POSTPROCESSING)) {
clang_tokens=clang_tu->get_tokens(0, parse_thread_buffer.bytes()-1);
parse_mutex.unlock();
parse_postprocess();
}
else
parse_mutex.unlock();
}
else {
parse_state=ParseState::STOP;
parse_mutex.unlock();
parse_error();
}
}
else
parse_done();
parse_mutex.unlock();
}
}
});
}
void Source::ClangViewParse::soft_reparse() {
parse_thread_mapped=false;
parsed=false;
if(parse_state!=ParseState::WORKING)
return;
parse_process_state=ParseProcessState::IDLE;
delayed_reparse_connection.disconnect();
delayed_reparse_connection=Glib::signal_timeout().connect([this]() {
parsed=false;
parse_thread_go=true;
set_status("parsing...");
auto expected=ParseProcessState::IDLE;
if(parse_process_state.compare_exchange_strong(expected, ParseProcessState::STARTING))
set_status("parsing...");
return false;
}, 1000);
}
@ -655,7 +662,7 @@ Source::ClangViewParse(file_path, project_path, language), autocomplete_cancel_s
delete this;
});
do_full_reparse.connect([this](){
init_parse();
parse_initialize();
full_reparse_running=false;
});
}
@ -711,9 +718,8 @@ void Source::ClangViewAutocomplete::start_autocomplete() {
}
void Source::ClangViewAutocomplete::autocomplete() {
if(parse_thread_stop) {
if(parse_state!=ParseState::WORKING)
return;
}
if(!autocomplete_starting) {
autocomplete_starting=true;
@ -815,14 +821,16 @@ void Source::ClangViewAutocomplete::autocomplete() {
pos--;
}
autocomplete_thread=std::thread([this, ac_data, line_nr, column_nr, buffer](){
parsing_mutex.lock();
if(!parse_thread_stop)
parse_mutex.lock();
if(parse_state==ParseState::WORKING) {
parse_process_state=ParseProcessState::IDLE;
*ac_data=get_autocomplete_suggestions(buffer->raw(), line_nr, column_nr);
if(!parse_thread_stop)
}
if(parse_state==ParseState::WORKING)
autocomplete_done();
else
autocomplete_fail();
parsing_mutex.unlock();
parse_mutex.unlock();
});
}
}
@ -831,7 +839,8 @@ std::vector<Source::ClangViewAutocomplete::AutoCompleteData> Source::ClangViewAu
std::vector<AutoCompleteData> suggestions;
auto results=clang_tu->get_code_completions(buffer, line_number, column);
if(results.cx_results==NULL) {
parse_thread_stop=true;
auto expected=ParseState::WORKING;
parse_state.compare_exchange_strong(expected, ParseState::RESTARTING);
return suggestions;
}
@ -863,7 +872,7 @@ std::vector<Source::ClangViewAutocomplete::AutoCompleteData> Source::ClangViewAu
void Source::ClangViewAutocomplete::async_delete() {
parsing_in_progress->cancel("canceled, freeing resources in the background");
parse_thread_stop=true;
parse_state=ParseState::STOP;
delete_thread=std::thread([this](){
//TODO: Is it possible to stop the clang-process in progress?
if(full_reparse_thread.joinable())
@ -877,10 +886,15 @@ void Source::ClangViewAutocomplete::async_delete() {
}
bool Source::ClangViewAutocomplete::full_reparse() {
if(!full_reparse_running && !parse_error) {
if(!full_reparse_running) {
auto expected=ParseState::WORKING;
if(!parse_state.compare_exchange_strong(expected, ParseState::RESTARTING)) {
expected=ParseState::RESTARTING;
if(!parse_state.compare_exchange_strong(expected, ParseState::RESTARTING))
return false;
}
soft_reparse_needed=false;
full_reparse_running=true;
parse_thread_stop=true;
if(full_reparse_thread.joinable())
full_reparse_thread.join();
full_reparse_thread=std::thread([this](){

26
src/source_clang.h

@ -12,6 +12,9 @@
namespace Source {
class ClangViewParse : public View {
protected:
enum class ParseProcessState {IDLE, STARTING, PREPROCESSING, PROCESSING, POSTPROCESSING};
enum class ParseState {WORKING, RESTARTING, STOP};
public:
class TokenRange {
public:
@ -28,16 +31,12 @@ namespace Source {
void soft_reparse() override;
protected:
void init_parse();
void parse_initialize();
std::unique_ptr<clang::TranslationUnit> clang_tu;
std::mutex parsing_mutex;
std::unique_ptr<clang::Tokens> clang_tokens;
sigc::connection delayed_reparse_connection;
std::shared_ptr<Terminal::InProgress> parsing_in_progress;
std::thread parse_thread;
std::atomic<bool> parse_thread_stop;
std::atomic<bool> parse_error;
void show_diagnostic_tooltips(const Gdk::Rectangle &rectangle) override;
void show_type_tooltips(const Gdk::Rectangle &rectangle) override;
@ -49,24 +48,25 @@ namespace Source {
std::set<int> diagnostic_offsets;
std::vector<FixIt> fix_its;
std::thread parse_thread;
std::mutex parse_mutex;
std::atomic<ParseProcessState> parse_process_state;
std::atomic<ParseState> parse_state;
sigc::connection parse_done_connection;
sigc::connection parse_start_connection;
sigc::connection parse_fail_connection;
private:
Glib::Dispatcher parse_preprocess;
Glib::Dispatcher parse_postprocess;
Glib::Dispatcher parse_error;
Glib::ustring parse_thread_buffer;
void update_syntax();
std::set<std::string> last_syntax_tags;
void update_diagnostics();
static clang::Index clang_index;
std::vector<std::string> get_compilation_commands();
Glib::Dispatcher parse_done;
Glib::Dispatcher parse_start;
Glib::Dispatcher parse_fail;
Glib::ustring parse_thread_buffer;
std::mutex parse_thread_buffer_mutex;
std::atomic<bool> parse_thread_go;
std::atomic<bool> parse_thread_mapped;
};
class ClangViewAutocomplete : public ClangViewParse {

Loading…
Cancel
Save