Browse Source

Added Dispatcher class for simpler dispatching of functions from worker threads to gui thread. Also got rid of the Project-singleton by replacing its function with static functions

merge-requests/365/head
eidheim 10 years ago
parent
commit
e667a38640
  1. 2
      src/CMakeLists.txt
  2. 30
      src/dispatcher.cc
  3. 20
      src/dispatcher.h
  4. 248
      src/project.cc
  5. 41
      src/project.h
  6. 59
      src/terminal.cc
  7. 12
      src/terminal.h
  8. 47
      src/window.cc

2
src/CMakeLists.txt

@ -86,6 +86,8 @@ set(source_files juci.h
dialogs.cc dialogs.cc
project.h project.h
project.cc project.cc
dispatcher.h
dispatcher.cc
../libclangmm/src/CodeCompleteResults.cc ../libclangmm/src/CodeCompleteResults.cc
../libclangmm/src/CompilationDatabase.cc ../libclangmm/src/CompilationDatabase.cc

30
src/dispatcher.cc

@ -0,0 +1,30 @@
#include "dispatcher.h"
Dispatcher::Dispatcher() {
connection=dispatcher.connect([this] {
functions_mutex.lock();
for(auto &function: functions) {
function();
}
functions.clear();
functions_mutex.unlock();
});
}
Dispatcher::~Dispatcher() {
disconnect();
functions_mutex.lock();
functions.clear();
functions_mutex.unlock();
}
void Dispatcher::add(std::function<void()> function) {
functions_mutex.lock();
functions.emplace_back(function);
functions_mutex.unlock();
dispatcher();
}
void Dispatcher::disconnect() {
connection.disconnect();
}

20
src/dispatcher.h

@ -0,0 +1,20 @@
#ifndef DISPATCHER_H_
#define DISPATCHER_H_
#include <gtkmm.h>
#include <mutex>
#include <vector>
class Dispatcher {
private:
std::vector<std::function<void()>> functions;
std::mutex functions_mutex;
Glib::Dispatcher dispatcher;
sigc::connection connection;
public:
Dispatcher();
~Dispatcher();
void add(std::function<void()> function);
void disconnect();
};
#endif /* DISPATCHER_H_ */

248
src/project.cc

@ -4,83 +4,74 @@
#include "filesystem.h" #include "filesystem.h"
#include <fstream> #include <fstream>
#include "menu.h" #include "menu.h"
#include "notebook.h"
#ifdef JUCI_ENABLE_DEBUG #ifdef JUCI_ENABLE_DEBUG
#include "debug.h" #include "debug.h"
#endif #endif
Project::Project() : notebook(Notebook::get()), compiling(false), debugging(false) { std::unordered_map<std::string, std::string> Project::run_arguments;
debug_update_stop.connect([this](){ std::unordered_map<std::string, std::string> Project::debug_run_arguments;
debug_stop_mutex.lock(); std::atomic<bool> Project::compiling;
for(int c=0;c<notebook.size();c++) { std::atomic<bool> Project::debugging;
auto view=notebook.get_view(c); std::pair<boost::filesystem::path, std::pair<int, int> > Project::debug_stop;
if(view->file_path==debug_last_stop_file_path) { boost::filesystem::path Project::debug_last_stop_file_path;
view->get_source_buffer()->remove_source_marks(view->get_buffer()->begin(), view->get_buffer()->end(), "debug_stop"); std::unique_ptr<Gtk::Label> Project::debug_status_label;
break;
} void Project::debug_update_status(const std::string &debug_status) {
if(debug_status.empty()) {
debug_status_label->set_text("");
auto &menu=Menu::get();
menu.actions["debug_stop"]->set_enabled(false);
menu.actions["debug_kill"]->set_enabled(false);
menu.actions["debug_step_over"]->set_enabled(false);
menu.actions["debug_step_into"]->set_enabled(false);
menu.actions["debug_step_out"]->set_enabled(false);
menu.actions["debug_backtrace"]->set_enabled(false);
menu.actions["debug_show_variables"]->set_enabled(false);
menu.actions["debug_run_command"]->set_enabled(false);
menu.actions["debug_goto_stop"]->set_enabled(false);
}
else {
debug_status_label->set_text("debug: "+debug_status);
auto &menu=Menu::get();
menu.actions["debug_stop"]->set_enabled();
menu.actions["debug_kill"]->set_enabled();
menu.actions["debug_step_over"]->set_enabled();
menu.actions["debug_step_into"]->set_enabled();
menu.actions["debug_step_out"]->set_enabled();
menu.actions["debug_backtrace"]->set_enabled();
menu.actions["debug_show_variables"]->set_enabled();
menu.actions["debug_run_command"]->set_enabled();
menu.actions["debug_goto_stop"]->set_enabled();
}
}
void Project::debug_update_stop() {
for(int c=0;c<Notebook::get().size();c++) {
auto view=Notebook::get().get_view(c);
if(view->file_path==debug_last_stop_file_path) {
view->get_source_buffer()->remove_source_marks(view->get_buffer()->begin(), view->get_buffer()->end(), "debug_stop");
break;
} }
//Add debug stop source mark }
for(int c=0;c<notebook.size();c++) { //Add debug stop source mark
auto view=notebook.get_view(c); for(int c=0;c<Notebook::get().size();c++) {
if(view->file_path==debug_stop.first) { auto view=Notebook::get().get_view(c);
if(debug_stop.second.first-1<view->get_buffer()->get_line_count()) { if(view->file_path==debug_stop.first) {
view->get_source_buffer()->create_source_mark("debug_stop", view->get_buffer()->get_iter_at_line(debug_stop.second.first-1)); if(debug_stop.second.first-1<view->get_buffer()->get_line_count()) {
debug_last_stop_file_path=debug_stop.first; view->get_source_buffer()->create_source_mark("debug_stop", view->get_buffer()->get_iter_at_line(debug_stop.second.first-1));
} debug_last_stop_file_path=debug_stop.first;
break;
} }
break;
} }
if(notebook.get_current_page()!=-1) }
notebook.get_current_view()->get_buffer()->place_cursor(notebook.get_current_view()->get_buffer()->get_insert()->get_iter()); if(Notebook::get().get_current_page()!=-1)
debug_stop_mutex.unlock(); Notebook::get().get_current_view()->get_buffer()->place_cursor(Notebook::get().get_current_view()->get_buffer()->get_insert()->get_iter());
});
#ifdef JUCI_ENABLE_DEBUG
auto &menu=Menu::get();
menu.actions["debug_stop"]->set_enabled(false);
menu.actions["debug_kill"]->set_enabled(false);
menu.actions["debug_step_over"]->set_enabled(false);
menu.actions["debug_step_into"]->set_enabled(false);
menu.actions["debug_step_out"]->set_enabled(false);
menu.actions["debug_backtrace"]->set_enabled(false);
menu.actions["debug_show_variables"]->set_enabled(false);
menu.actions["debug_run_command"]->set_enabled(false);
menu.actions["debug_goto_stop"]->set_enabled(false);
#endif
debug_update_status.connect([this](){
debug_status_mutex.lock();
if(debug_status.empty()) {
debug_status_label.set_text("");
auto &menu=Menu::get();
menu.actions["debug_stop"]->set_enabled(false);
menu.actions["debug_kill"]->set_enabled(false);
menu.actions["debug_step_over"]->set_enabled(false);
menu.actions["debug_step_into"]->set_enabled(false);
menu.actions["debug_step_out"]->set_enabled(false);
menu.actions["debug_backtrace"]->set_enabled(false);
menu.actions["debug_show_variables"]->set_enabled(false);
menu.actions["debug_run_command"]->set_enabled(false);
menu.actions["debug_goto_stop"]->set_enabled(false);
}
else {
debug_status_label.set_text("debug: "+debug_status);
auto &menu=Menu::get();
menu.actions["debug_stop"]->set_enabled();
menu.actions["debug_kill"]->set_enabled();
menu.actions["debug_step_over"]->set_enabled();
menu.actions["debug_step_into"]->set_enabled();
menu.actions["debug_step_out"]->set_enabled();
menu.actions["debug_backtrace"]->set_enabled();
menu.actions["debug_show_variables"]->set_enabled();
menu.actions["debug_run_command"]->set_enabled();
menu.actions["debug_goto_stop"]->set_enabled();
}
debug_status_mutex.unlock();
});
} }
std::unique_ptr<Project::Language> Project::get_language() { std::unique_ptr<Project::Language> Project::get_language() {
if(notebook.get_current_page()!=-1) { if(Notebook::get().get_current_page()!=-1) {
auto language_id=notebook.get_current_view()->language->get_id(); auto language_id=Notebook::get().get_current_view()->language->get_id();
if(language_id=="markdown") if(language_id=="markdown")
return std::unique_ptr<Project::Language>(new Project::Markdown()); return std::unique_ptr<Project::Language>(new Project::Markdown());
if(language_id=="python") if(language_id=="python")
@ -96,8 +87,8 @@ std::unique_ptr<Project::Language> Project::get_language() {
std::unique_ptr<CMake> Project::Clang::get_cmake() { std::unique_ptr<CMake> Project::Clang::get_cmake() {
boost::filesystem::path path; boost::filesystem::path path;
if(notebook.get_current_page()!=-1) if(Notebook::get().get_current_page()!=-1)
path=notebook.get_current_view()->file_path.parent_path(); path=Notebook::get().get_current_view()->file_path.parent_path();
else else
path=Directories::get().current_path; path=Directories::get().current_path;
if(path.empty()) if(path.empty())
@ -116,13 +107,13 @@ std::pair<std::string, std::string> Project::Clang::get_run_arguments() {
return {"", ""}; return {"", ""};
auto project_path=cmake->project_path.string(); auto project_path=cmake->project_path.string();
auto run_arguments_it=Project::get().run_arguments.find(project_path); auto run_arguments_it=run_arguments.find(project_path);
std::string arguments; std::string arguments;
if(run_arguments_it!=Project::get().run_arguments.end()) if(run_arguments_it!=run_arguments.end())
arguments=run_arguments_it->second; arguments=run_arguments_it->second;
if(arguments.empty()) { if(arguments.empty()) {
auto executable=cmake->get_executable(notebook.get_current_page()!=-1?notebook.get_current_view()->file_path:"").string(); auto executable=cmake->get_executable(Notebook::get().get_current_page()!=-1?Notebook::get().get_current_view()->file_path:"").string();
if(executable!="") { if(executable!="") {
auto project_path=cmake->project_path; auto project_path=cmake->project_path;
@ -149,10 +140,10 @@ void Project::Clang::compile() {
auto default_build_path=CMake::get_default_build_path(cmake->project_path); auto default_build_path=CMake::get_default_build_path(cmake->project_path);
if(default_build_path.empty()) if(default_build_path.empty())
return; return;
Project::get().compiling=true; compiling=true;
Terminal::get().print("Compiling project "+cmake->project_path.string()+"\n"); Terminal::get().print("Compiling project "+cmake->project_path.string()+"\n");
Terminal::get().async_process(Config::get().terminal.make_command, default_build_path, [this](int exit_status) { Terminal::get().async_process(Config::get().terminal.make_command, default_build_path, [this](int exit_status) {
Project::get().compiling=false; compiling=false;
}); });
} }
@ -166,13 +157,13 @@ void Project::Clang::compile_and_run() {
if(default_build_path.empty()) if(default_build_path.empty())
return; return;
auto run_arguments_it=Project::get().run_arguments.find(project_path.string()); auto run_arguments_it=run_arguments.find(project_path.string());
std::string arguments; std::string arguments;
if(run_arguments_it!=Project::get().run_arguments.end()) if(run_arguments_it!=run_arguments.end())
arguments=run_arguments_it->second; arguments=run_arguments_it->second;
if(arguments.empty()) { if(arguments.empty()) {
arguments=cmake->get_executable(notebook.get_current_page()!=-1?notebook.get_current_view()->file_path:"").string(); arguments=cmake->get_executable(Notebook::get().get_current_page()!=-1?Notebook::get().get_current_view()->file_path:"").string();
if(arguments.empty()) { if(arguments.empty()) {
Terminal::get().print("Could not find add_executable in the following paths:\n"); Terminal::get().print("Could not find add_executable in the following paths:\n");
for(auto &path: cmake->paths) for(auto &path: cmake->paths)
@ -186,10 +177,10 @@ void Project::Clang::compile_and_run() {
arguments=filesystem::escape_argument(arguments); arguments=filesystem::escape_argument(arguments);
} }
Project::get().compiling=true; compiling=true;
Terminal::get().print("Compiling and running "+arguments+"\n"); Terminal::get().print("Compiling and running "+arguments+"\n");
Terminal::get().async_process(Config::get().terminal.make_command, default_build_path, [this, arguments, default_build_path](int exit_status){ Terminal::get().async_process(Config::get().terminal.make_command, default_build_path, [this, arguments, default_build_path](int exit_status){
Project::get().compiling=false; compiling=false;
if(exit_status==EXIT_SUCCESS) { if(exit_status==EXIT_SUCCESS) {
Terminal::get().async_process(arguments, default_build_path, [this, arguments](int exit_status){ Terminal::get().async_process(arguments, default_build_path, [this, arguments](int exit_status){
Terminal::get().async_print(arguments+" returned: "+std::to_string(exit_status)+'\n'); Terminal::get().async_print(arguments+" returned: "+std::to_string(exit_status)+'\n');
@ -205,13 +196,13 @@ std::pair<std::string, std::string> Project::Clang::debug_get_run_arguments() {
return {"", ""}; return {"", ""};
auto project_path=cmake->project_path.string(); auto project_path=cmake->project_path.string();
auto run_arguments_it=Project::get().debug_run_arguments.find(project_path); auto run_arguments_it=debug_run_arguments.find(project_path);
std::string arguments; std::string arguments;
if(run_arguments_it!=Project::get().debug_run_arguments.end()) if(run_arguments_it!=debug_run_arguments.end())
arguments=run_arguments_it->second; arguments=run_arguments_it->second;
if(arguments.empty()) { if(arguments.empty()) {
auto executable=cmake->get_executable(notebook.get_current_page()!=-1?notebook.get_current_view()->file_path:"").string(); auto executable=cmake->get_executable(Notebook::get().get_current_page()!=-1?Notebook::get().get_current_view()->file_path:"").string();
if(executable!="") { if(executable!="") {
auto project_path=cmake->project_path; auto project_path=cmake->project_path;
@ -242,13 +233,13 @@ void Project::Clang::debug_start() {
if(!CMake::create_debug_build(project_path)) if(!CMake::create_debug_build(project_path))
return; return;
auto run_arguments_it=Project::get().debug_run_arguments.find(project_path.string()); auto run_arguments_it=debug_run_arguments.find(project_path.string());
std::string run_arguments; std::string run_arguments;
if(run_arguments_it!=Project::get().debug_run_arguments.end()) if(run_arguments_it!=debug_run_arguments.end())
run_arguments=run_arguments_it->second; run_arguments=run_arguments_it->second;
if(run_arguments.empty()) { if(run_arguments.empty()) {
run_arguments=cmake->get_executable(notebook.get_current_page()!=-1?notebook.get_current_view()->file_path:"").string(); run_arguments=cmake->get_executable(Notebook::get().get_current_page()!=-1?Notebook::get().get_current_view()->file_path:"").string();
if(run_arguments.empty()) { if(run_arguments.empty()) {
Terminal::get().print("Could not find add_executable in the following paths:\n"); Terminal::get().print("Could not find add_executable in the following paths:\n");
for(auto &path: cmake->paths) for(auto &path: cmake->paths)
@ -263,8 +254,8 @@ void Project::Clang::debug_start() {
} }
auto breakpoints=std::make_shared<std::vector<std::pair<boost::filesystem::path, int> > >(); auto breakpoints=std::make_shared<std::vector<std::pair<boost::filesystem::path, int> > >();
for(int c=0;c<notebook.size();c++) { for(int c=0;c<Notebook::get().size();c++) {
auto view=notebook.get_view(c); auto view=Notebook::get().get_view(c);
if(project_path==view->project_path) { if(project_path==view->project_path) {
auto iter=view->get_buffer()->begin(); auto iter=view->get_buffer()->begin();
if(view->get_source_buffer()->get_source_marks_at_iter(iter, "debug_breakpoint").size()>0) if(view->get_source_buffer()->get_source_marks_at_iter(iter, "debug_breakpoint").size()>0)
@ -274,30 +265,29 @@ void Project::Clang::debug_start() {
} }
} }
Project::get().debugging=true; debugging=true;
Terminal::get().print("Compiling and debugging "+run_arguments+"\n"); Terminal::get().print("Compiling and debugging "+run_arguments+"\n");
Terminal::get().async_process(Config::get().terminal.make_command, debug_build_path, [this, breakpoints, run_arguments, debug_build_path](int exit_status){ Terminal::get().async_process(Config::get().terminal.make_command, debug_build_path, [this, breakpoints, run_arguments, debug_build_path](int exit_status){
if(exit_status!=EXIT_SUCCESS) if(exit_status!=EXIT_SUCCESS)
Project::get().debugging=false; debugging=false;
else { else {
debug_start_mutex.lock(); debug_start_mutex.lock();
Debug::get().start(run_arguments, debug_build_path, *breakpoints, [this, run_arguments](int exit_status){ Debug::get().start(run_arguments, debug_build_path, *breakpoints, [this, run_arguments](int exit_status){
Project::get().debugging=false; debugging=false;
Terminal::get().async_print(run_arguments+" returned: "+std::to_string(exit_status)+'\n'); Terminal::get().async_print(run_arguments+" returned: "+std::to_string(exit_status)+'\n');
}, [this](const std::string &status) { }, [this](const std::string &status) {
auto &project=Project::get(); dispatcher.add([this, status] {
project.debug_status_mutex.lock(); debug_update_status(status);
project.debug_status=status; });
project.debug_status_mutex.unlock(); }, [this](const boost::filesystem::path &file_path, int line_nr, int line_index) {
project.debug_update_status(); dispatcher.add([this, file_path, line_nr, line_index] {
}, [this](const boost::filesystem::path &file_path, int line_nr, int line_index) { Project::debug_stop.first=file_path;
auto &project=Project::get(); Project::debug_stop.second.first=line_nr;
project.debug_stop_mutex.lock(); Project::debug_stop.second.second=line_index;
project.debug_stop.first=file_path;
project.debug_stop.second.first=line_nr; debug_update_stop();
project.debug_stop.second.second=line_index; });
project.debug_stop_mutex.unlock();
project.debug_update_stop();
}); });
debug_start_mutex.unlock(); debug_start_mutex.unlock();
} }
@ -309,35 +299,35 @@ void Project::Clang::debug_continue() {
} }
void Project::Clang::debug_stop() { void Project::Clang::debug_stop() {
if(Project::get().debugging) if(debugging)
Debug::get().stop(); Debug::get().stop();
} }
void Project::Clang::debug_kill() { void Project::Clang::debug_kill() {
if(Project::get().debugging) if(debugging)
Debug::get().kill(); Debug::get().kill();
} }
void Project::Clang::debug_step_over() { void Project::Clang::debug_step_over() {
if(Project::get().debugging) if(debugging)
Debug::get().step_over(); Debug::get().step_over();
} }
void Project::Clang::debug_step_into() { void Project::Clang::debug_step_into() {
if(Project::get().debugging) if(debugging)
Debug::get().step_into(); Debug::get().step_into();
} }
void Project::Clang::debug_step_out() { void Project::Clang::debug_step_out() {
if(Project::get().debugging) if(debugging)
Debug::get().step_out(); Debug::get().step_out();
} }
void Project::Clang::debug_backtrace() { void Project::Clang::debug_backtrace() {
if(Project::get().debugging && notebook.get_current_page()!=-1) { if(debugging && Notebook::get().get_current_page()!=-1) {
auto backtrace=Debug::get().get_backtrace(); auto backtrace=Debug::get().get_backtrace();
auto view=notebook.get_current_view(); auto view=Notebook::get().get_current_view();
auto iter=view->get_iter_for_dialog(); auto iter=view->get_iter_for_dialog();
view->selection_dialog=std::unique_ptr<SelectionDialog>(new SelectionDialog(*view, view->get_buffer()->create_mark(iter), true, true)); view->selection_dialog=std::unique_ptr<SelectionDialog>(new SelectionDialog(*view, view->get_buffer()->create_mark(iter), true, true));
auto rows=std::make_shared<std::unordered_map<std::string, Debug::Frame> >(); auto rows=std::make_shared<std::unordered_map<std::string, Debug::Frame> >();
@ -364,9 +354,9 @@ void Project::Clang::debug_backtrace() {
view->selection_dialog->on_select=[this, rows](const std::string& selected, bool hide_window) { view->selection_dialog->on_select=[this, rows](const std::string& selected, bool hide_window) {
auto frame=rows->at(selected); auto frame=rows->at(selected);
if(!frame.file_path.empty()) { if(!frame.file_path.empty()) {
notebook.open(frame.file_path); Notebook::get().open(frame.file_path);
if(notebook.get_current_page()!=-1) { if(Notebook::get().get_current_page()!=-1) {
auto view=notebook.get_current_view(); auto view=Notebook::get().get_current_view();
Debug::get().select_frame(frame.index); Debug::get().select_frame(frame.index);
@ -374,7 +364,7 @@ void Project::Clang::debug_backtrace() {
while(g_main_context_pending(NULL)) while(g_main_context_pending(NULL))
g_main_context_iteration(NULL, false); g_main_context_iteration(NULL, false);
if(notebook.get_current_page()!=-1 && notebook.get_current_view()==view) if(Notebook::get().get_current_page()!=-1 && Notebook::get().get_current_view()==view)
view->scroll_to(view->get_buffer()->get_insert(), 0.0, 1.0, 0.5); view->scroll_to(view->get_buffer()->get_insert(), 0.0, 1.0, 0.5);
} }
} }
@ -384,10 +374,10 @@ void Project::Clang::debug_backtrace() {
} }
void Project::Clang::debug_show_variables() { void Project::Clang::debug_show_variables() {
if(Project::get().debugging && notebook.get_current_page()!=-1) { if(debugging && Notebook::get().get_current_page()!=-1) {
auto variables=Debug::get().get_variables(); auto variables=Debug::get().get_variables();
auto view=notebook.get_current_view(); auto view=Notebook::get().get_current_view();
auto iter=view->get_iter_for_dialog(); auto iter=view->get_iter_for_dialog();
view->selection_dialog=std::unique_ptr<SelectionDialog>(new SelectionDialog(*view, view->get_buffer()->create_mark(iter), true, true)); view->selection_dialog=std::unique_ptr<SelectionDialog>(new SelectionDialog(*view, view->get_buffer()->create_mark(iter), true, true));
auto rows=std::make_shared<std::unordered_map<std::string, Debug::Variable> >(); auto rows=std::make_shared<std::unordered_map<std::string, Debug::Variable> >();
@ -404,9 +394,9 @@ void Project::Clang::debug_show_variables() {
view->selection_dialog->on_select=[this, rows](const std::string& selected, bool hide_window) { view->selection_dialog->on_select=[this, rows](const std::string& selected, bool hide_window) {
auto variable=rows->at(selected); auto variable=rows->at(selected);
if(!variable.file_path.empty()) { if(!variable.file_path.empty()) {
notebook.open(variable.file_path); Notebook::get().open(variable.file_path);
if(notebook.get_current_page()!=-1) { if(Notebook::get().get_current_page()!=-1) {
auto view=notebook.get_current_view(); auto view=Notebook::get().get_current_view();
Debug::get().select_frame(variable.frame_index, variable.thread_index_id); Debug::get().select_frame(variable.frame_index, variable.thread_index_id);
@ -414,7 +404,7 @@ void Project::Clang::debug_show_variables() {
while(g_main_context_pending(NULL)) while(g_main_context_pending(NULL))
g_main_context_iteration(NULL, false); g_main_context_iteration(NULL, false);
if(notebook.get_current_page()!=-1 && notebook.get_current_view()==view) if(Notebook::get().get_current_page()!=-1 && Notebook::get().get_current_view()==view)
view->scroll_to(view->get_buffer()->get_insert(), 0.0, 1.0, 0.5); view->scroll_to(view->get_buffer()->get_insert(), 0.0, 1.0, 0.5);
} }
} }
@ -430,8 +420,8 @@ void Project::Clang::debug_show_variables() {
debug_variable_tooltips.hide(); debug_variable_tooltips.hide();
return; return;
} }
if(notebook.get_current_page()!=-1) { if(Notebook::get().get_current_page()!=-1) {
auto view=notebook.get_current_view(); auto view=Notebook::get().get_current_view();
debug_variable_tooltips.clear(); debug_variable_tooltips.clear();
auto create_tooltip_buffer=[this, rows, view, selected]() { auto create_tooltip_buffer=[this, rows, view, selected]() {
auto variable=rows->at(selected); auto variable=rows->at(selected);
@ -462,7 +452,7 @@ void Project::Clang::debug_show_variables() {
} }
void Project::Clang::debug_run_command(const std::string &command) { void Project::Clang::debug_run_command(const std::string &command) {
if(Project::get().debugging) { if(debugging) {
auto command_return=Debug::get().run_command(command); auto command_return=Debug::get().run_command(command);
Terminal::get().async_print(command_return.first); Terminal::get().async_print(command_return.first);
Terminal::get().async_print(command_return.second, true); Terminal::get().async_print(command_return.second, true);
@ -498,7 +488,7 @@ void Project::Markdown::compile_and_run() {
} }
std::stringstream stdin_stream, stdout_stream; std::stringstream stdin_stream, stdout_stream;
auto exit_status=Terminal::get().process(stdin_stream, stdout_stream, "markdown "+notebook.get_current_view()->file_path.string()); auto exit_status=Terminal::get().process(stdin_stream, stdout_stream, "markdown "+Notebook::get().get_current_view()->file_path.string());
if(exit_status==0) { if(exit_status==0) {
boost::system::error_code ec; boost::system::error_code ec;
auto temp_path=boost::filesystem::temp_directory_path(ec); auto temp_path=boost::filesystem::temp_directory_path(ec);
@ -528,23 +518,23 @@ void Project::Markdown::compile_and_run() {
} }
void Project::Python::compile_and_run() { void Project::Python::compile_and_run() {
auto command="python "+notebook.get_current_view()->file_path.string(); auto command="python "+Notebook::get().get_current_view()->file_path.string();
Terminal::get().print("Running "+command+"\n"); Terminal::get().print("Running "+command+"\n");
Terminal::get().async_process(command, notebook.get_current_view()->file_path.parent_path(), [command](int exit_status) { Terminal::get().async_process(command, Notebook::get().get_current_view()->file_path.parent_path(), [command](int exit_status) {
Terminal::get().async_print(command+" returned: "+std::to_string(exit_status)+'\n'); Terminal::get().async_print(command+" returned: "+std::to_string(exit_status)+'\n');
}); });
} }
void Project::JavaScript::compile_and_run() { void Project::JavaScript::compile_and_run() {
auto command="node "+notebook.get_current_view()->file_path.string(); auto command="node "+Notebook::get().get_current_view()->file_path.string();
Terminal::get().print("Running "+command+"\n"); Terminal::get().print("Running "+command+"\n");
Terminal::get().async_process(command, notebook.get_current_view()->file_path.parent_path(), [command](int exit_status) { Terminal::get().async_process(command, Notebook::get().get_current_view()->file_path.parent_path(), [command](int exit_status) {
Terminal::get().async_print(command+" returned: "+std::to_string(exit_status)+'\n'); Terminal::get().async_print(command+" returned: "+std::to_string(exit_status)+'\n');
}); });
} }
void Project::HTML::compile_and_run() { void Project::HTML::compile_and_run() {
auto uri=notebook.get_current_view()->file_path.string(); auto uri=Notebook::get().get_current_view()->file_path.string();
#ifdef __APPLE__ #ifdef __APPLE__
Terminal::get().process("open \""+uri+"\""); Terminal::get().process("open \""+uri+"\"");
#else #else

41
src/project.h

@ -2,43 +2,31 @@
#define JUCI_PROJECT_H_ #define JUCI_PROJECT_H_
#include <gtkmm.h> #include <gtkmm.h>
#include "notebook.h"
#include "cmake.h" #include "cmake.h"
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include "directories.h" #include "directories.h"
#include <atomic> #include <atomic>
#include <mutex> #include <mutex>
#include "tooltips.h" #include "tooltips.h"
#include "dispatcher.h"
#include <iostream>
class Project { class Project {
private: private:
boost::filesystem::path debug_last_stop_file_path; static boost::filesystem::path debug_last_stop_file_path;
std::string debug_status;
std::mutex debug_status_mutex;
Glib::Dispatcher debug_update_status;
Project();
Notebook &notebook; //convenience reference
public: public:
static Project &get() { static std::unordered_map<std::string, std::string> run_arguments;
static Project singleton; static std::unordered_map<std::string, std::string> debug_run_arguments;
return singleton; static std::atomic<bool> compiling;
} static std::atomic<bool> debugging;
static std::pair<boost::filesystem::path, std::pair<int, int> > debug_stop;
Gtk::Label debug_status_label; static void debug_update_stop();
std::pair<boost::filesystem::path, std::pair<int, int> > debug_stop; static std::unique_ptr<Gtk::Label> debug_status_label;
std::mutex debug_stop_mutex; static void debug_update_status(const std::string &debug_status);
Glib::Dispatcher debug_update_stop;
std::unordered_map<std::string, std::string> run_arguments;
std::unordered_map<std::string, std::string> debug_run_arguments;
std::atomic<bool> compiling;
std::atomic<bool> debugging;
class Language { class Language {
protected:
Notebook &notebook; //convenience reference
public: public:
Language() : notebook(Notebook::get()) {} Language() {}
virtual ~Language() {} virtual ~Language() {}
virtual std::pair<std::string, std::string> get_run_arguments() {return {"", ""};} virtual std::pair<std::string, std::string> get_run_arguments() {return {"", ""};}
@ -63,8 +51,11 @@ public:
}; };
class Clang : public Language { class Clang : public Language {
private:
Dispatcher dispatcher;
public: public:
Clang() : Language() {} Clang() : Language() {}
~Clang() { dispatcher.disconnect(); }
std::unique_ptr<CMake> get_cmake(); std::unique_ptr<CMake> get_cmake();
@ -121,7 +112,7 @@ public:
void compile_and_run() override; void compile_and_run() override;
}; };
std::unique_ptr<Language> get_language(); static std::unique_ptr<Language> get_language();
}; };
#endif // JUCI_PROJECT_H_ #endif // JUCI_PROJECT_H_

59
src/terminal.cc

@ -7,9 +7,6 @@
#endif #endif
Terminal::InProgress::InProgress(const std::string& start_msg): stop(false) { Terminal::InProgress::InProgress(const std::string& start_msg): stop(false) {
waiting_print.connect([this](){
Terminal::get().async_print(line_nr-1, ".");
});
start(start_msg); start(start_msg);
} }
@ -24,8 +21,11 @@ void Terminal::InProgress::start(const std::string& msg) {
wait_thread=std::thread([this](){ wait_thread=std::thread([this](){
size_t c=0; size_t c=0;
while(!stop) { while(!stop) {
if(c%100==0) if(c%100==0) {
waiting_print(); dispatcher.add([this] {
Terminal::get().print(line_nr-1, ".");
});
}
std::this_thread::sleep_for(std::chrono::milliseconds(10)); std::this_thread::sleep_for(std::chrono::milliseconds(10));
c++; c++;
} }
@ -35,39 +35,24 @@ void Terminal::InProgress::start(const std::string& msg) {
void Terminal::InProgress::done(const std::string& msg) { void Terminal::InProgress::done(const std::string& msg) {
if(!stop) { if(!stop) {
stop=true; stop=true;
Terminal::get().async_print(line_nr-1, msg); dispatcher.add([this, msg] {
Terminal::get().print(line_nr-1, msg);
});
} }
} }
void Terminal::InProgress::cancel(const std::string& msg) { void Terminal::InProgress::cancel(const std::string& msg) {
if(!stop) { if(!stop) {
stop=true; stop=true;
Terminal::get().async_print(line_nr-1, msg); dispatcher.add([this, msg] {
Terminal::get().print(line_nr-1, msg);
});
} }
} }
Terminal::Terminal() { Terminal::Terminal() {
bold_tag=get_buffer()->create_tag(); bold_tag=get_buffer()->create_tag();
bold_tag->property_weight()=PANGO_WEIGHT_BOLD; bold_tag->property_weight()=PANGO_WEIGHT_BOLD;
async_print_dispatcher.connect([this](){
async_print_strings_mutex.lock();
if(async_print_strings.size()>0) {
for(auto &string_bold: async_print_strings)
print(string_bold.first, string_bold.second);
async_print_strings.clear();
}
async_print_strings_mutex.unlock();
});
async_print_on_line_dispatcher.connect([this](){
async_print_on_line_strings_mutex.lock();
if(async_print_on_line_strings.size()>0) {
for(auto &line_string: async_print_on_line_strings)
print(line_string.first, line_string.second);
async_print_on_line_strings.clear();
}
async_print_on_line_strings_mutex.unlock();
});
} }
int Terminal::process(const std::string &command, const boost::filesystem::path &path, bool use_pipes) { int Terminal::process(const std::string &command, const boost::filesystem::path &path, bool use_pipes) {
@ -251,25 +236,9 @@ std::shared_ptr<Terminal::InProgress> Terminal::print_in_progress(std::string st
} }
void Terminal::async_print(const std::string &message, bool bold) { void Terminal::async_print(const std::string &message, bool bold) {
async_print_strings_mutex.lock(); dispatcher.add([this, message, bold] {
bool dispatch=true; Terminal::get().print(message, bold);
if(async_print_strings.size()>0) });
dispatch=false;
async_print_strings.emplace_back(message, bold);
async_print_strings_mutex.unlock();
if(dispatch)
async_print_dispatcher();
}
void Terminal::async_print(int line_nr, const std::string &message) {
async_print_on_line_strings_mutex.lock();
bool dispatch=true;
if(async_print_on_line_strings.size()>0)
dispatch=false;
async_print_on_line_strings.emplace_back(line_nr, message);
async_print_on_line_strings_mutex.unlock();
if(dispatch)
async_print_on_line_dispatcher();
} }
bool Terminal::on_key_press_event(GdkEventKey *event) { bool Terminal::on_key_press_event(GdkEventKey *event) {

12
src/terminal.h

@ -9,6 +9,7 @@
#include <atomic> #include <atomic>
#include <iostream> #include <iostream>
#include "process.hpp" #include "process.hpp"
#include "dispatcher.h"
class Terminal : public Gtk::TextView { class Terminal : public Gtk::TextView {
public: public:
@ -22,7 +23,8 @@ public:
void start(const std::string& msg); void start(const std::string& msg);
size_t line_nr; size_t line_nr;
std::atomic<bool> stop; std::atomic<bool> stop;
Glib::Dispatcher waiting_print; Dispatcher dispatcher;
std::thread wait_thread; std::thread wait_thread;
}; };
@ -44,16 +46,10 @@ public:
void print(size_t line_nr, const std::string &message); void print(size_t line_nr, const std::string &message);
std::shared_ptr<InProgress> print_in_progress(std::string start_msg); std::shared_ptr<InProgress> print_in_progress(std::string start_msg);
void async_print(const std::string &message, bool bold=false); void async_print(const std::string &message, bool bold=false);
void async_print(int line_nr, const std::string &message);
protected: protected:
bool on_key_press_event(GdkEventKey *event); bool on_key_press_event(GdkEventKey *event);
private: private:
Glib::Dispatcher async_print_dispatcher; Dispatcher dispatcher;
Glib::Dispatcher async_print_on_line_dispatcher;
std::vector<std::pair<std::string, bool> > async_print_strings;
std::vector<std::pair<int, std::string> > async_print_on_line_strings;
std::mutex async_print_strings_mutex;
std::mutex async_print_on_line_strings_mutex;
Glib::RefPtr<Gtk::TextTag> bold_tag; Glib::RefPtr<Gtk::TextTag> bold_tag;
std::vector<std::shared_ptr<Process> > processes; std::vector<std::shared_ptr<Process> > processes;

47
src/window.cc

@ -25,7 +25,11 @@ Window::Window() : notebook(Notebook::get()) {
JDEBUG("start"); JDEBUG("start");
set_title("juCi++"); set_title("juCi++");
set_events(Gdk::POINTER_MOTION_MASK|Gdk::FOCUS_CHANGE_MASK|Gdk::SCROLL_MASK|Gdk::LEAVE_NOTIFY_MASK); set_events(Gdk::POINTER_MOTION_MASK|Gdk::FOCUS_CHANGE_MASK|Gdk::SCROLL_MASK|Gdk::LEAVE_NOTIFY_MASK);
Project::debug_status_label=std::unique_ptr<Gtk::Label>(new Gtk::Label());
set_menu_actions(); set_menu_actions();
configure(); configure();
set_default_size(Config::get().window.default_size.first, Config::get().window.default_size.second); set_default_size(Config::get().window.default_size.first, Config::get().window.default_size.second);
@ -46,11 +50,12 @@ Window::Window() : notebook(Notebook::get()) {
terminal_vbox.pack_start(terminal_scrolled_window); terminal_vbox.pack_start(terminal_scrolled_window);
info_and_status_hbox.pack_start(notebook.info, Gtk::PACK_SHRINK); info_and_status_hbox.pack_start(notebook.info, Gtk::PACK_SHRINK);
#if GTK_VERSION_GE(3, 12) #if GTK_VERSION_GE(3, 12)
info_and_status_hbox.set_center_widget(Project::get().debug_status_label); info_and_status_hbox.set_center_widget(*Project::debug_status_label);
#else #else
Project::get().debug_status_label.set_halign(Gtk::Align::ALIGN_CENTER); Project::get().debug_status_label.set_halign(Gtk::Align::ALIGN_CENTER);
info_and_status_hbox.pack_start(Project::get().debug_status_label); info_and_status_hbox.pack_start(*Project::debug_status_label);
#endif #endif
info_and_status_hbox.pack_end(notebook.status, Gtk::PACK_SHRINK); info_and_status_hbox.pack_end(notebook.status, Gtk::PACK_SHRINK);
terminal_vbox.pack_end(info_and_status_hbox, Gtk::PACK_SHRINK); terminal_vbox.pack_end(info_and_status_hbox, Gtk::PACK_SHRINK);
@ -504,7 +509,7 @@ void Window::set_menu_actions() {
}); });
menu.add_action("project_set_run_arguments", [this]() { menu.add_action("project_set_run_arguments", [this]() {
auto project_language=Project::get().get_language(); auto project_language=Project::get_language();
auto run_arguments=std::make_shared<std::pair<std::string, std::string> >(project_language->get_run_arguments()); auto run_arguments=std::make_shared<std::pair<std::string, std::string> >(project_language->get_run_arguments());
if(run_arguments->second.empty()) if(run_arguments->second.empty())
return; return;
@ -517,7 +522,7 @@ void Window::set_menu_actions() {
}; };
label_it->update(0, ""); label_it->update(0, "");
entry_box.entries.emplace_back(run_arguments->second, [this, run_arguments](const std::string& content){ entry_box.entries.emplace_back(run_arguments->second, [this, run_arguments](const std::string& content){
Project::get().run_arguments[run_arguments->first]=content; Project::run_arguments[run_arguments->first]=content;
entry_box.hide(); entry_box.hide();
}, 50); }, 50);
auto entry_it=entry_box.entries.begin(); auto entry_it=entry_box.entries.begin();
@ -528,23 +533,23 @@ void Window::set_menu_actions() {
entry_box.show(); entry_box.show();
}); });
menu.add_action("compile_and_run", [this]() { menu.add_action("compile_and_run", [this]() {
if(Project::get().compiling) if(Project::compiling)
return; return;
if(Config::get().window.save_on_compile_or_run) if(Config::get().window.save_on_compile_or_run)
notebook.save_project_files(); notebook.save_project_files();
project_language=Project::get().get_language(); project_language=Project::get_language();
project_language->compile_and_run(); project_language->compile_and_run();
}); });
menu.add_action("compile", [this]() { menu.add_action("compile", [this]() {
if(Project::get().compiling) if(Project::compiling)
return; return;
if(Config::get().window.save_on_compile_or_run) if(Config::get().window.save_on_compile_or_run)
notebook.save_project_files(); notebook.save_project_files();
project_language=Project::get().get_language(); project_language=Project::get_language();
project_language->compile(); project_language->compile();
}); });
@ -585,7 +590,7 @@ void Window::set_menu_actions() {
#ifdef JUCI_ENABLE_DEBUG #ifdef JUCI_ENABLE_DEBUG
menu.add_action("debug_set_run_arguments", [this]() { menu.add_action("debug_set_run_arguments", [this]() {
auto project_language=Project::get().get_language(); auto project_language=Project::get_language();
auto run_arguments=std::make_shared<std::pair<std::string, std::string> >(project_language->debug_get_run_arguments()); auto run_arguments=std::make_shared<std::pair<std::string, std::string> >(project_language->debug_get_run_arguments());
if(run_arguments->second.empty()) if(run_arguments->second.empty())
return; return;
@ -598,7 +603,7 @@ void Window::set_menu_actions() {
}; };
label_it->update(0, ""); label_it->update(0, "");
entry_box.entries.emplace_back(run_arguments->second, [this, run_arguments](const std::string& content){ entry_box.entries.emplace_back(run_arguments->second, [this, run_arguments](const std::string& content){
Project::get().debug_run_arguments[run_arguments->first]=content; Project::debug_run_arguments[run_arguments->first]=content;
entry_box.hide(); entry_box.hide();
}, 50); }, 50);
auto entry_it=entry_box.entries.begin(); auto entry_it=entry_box.entries.begin();
@ -609,7 +614,7 @@ void Window::set_menu_actions() {
entry_box.show(); entry_box.show();
}); });
menu.add_action("debug_start_continue", [this](){ menu.add_action("debug_start_continue", [this](){
if(Project::get().debugging) { if(Project::debugging) {
project_language->debug_continue(); project_language->debug_continue();
return; return;
} }
@ -617,7 +622,7 @@ void Window::set_menu_actions() {
if(Config::get().window.save_on_compile_or_run) if(Config::get().window.save_on_compile_or_run)
notebook.save_project_files(); notebook.save_project_files();
project_language=Project::get().get_language(); project_language=Project::get_language();
project_language->debug_start(); project_language->debug_start();
}); });
@ -687,18 +692,14 @@ void Window::set_menu_actions() {
} }
}); });
menu.add_action("debug_goto_stop", [this](){ menu.add_action("debug_goto_stop", [this](){
if(Project::get().debugging) { if(Project::debugging) {
auto &project=Project::get(); if(!Project::debug_stop.first.empty()) {
project.debug_stop_mutex.lock(); notebook.open(Project::debug_stop.first);
auto debug_stop_copy=project.debug_stop;
project.debug_stop_mutex.unlock();
if(!debug_stop_copy.first.empty()) {
notebook.open(debug_stop_copy.first);
if(notebook.get_current_page()!=-1) { if(notebook.get_current_page()!=-1) {
auto view=notebook.get_current_view(); auto view=notebook.get_current_view();
int line_nr=debug_stop_copy.second.first-1; int line_nr=Project::debug_stop.second.first-1;
int line_index=debug_stop_copy.second.second-1; int line_index=Project::debug_stop.second.second-1;
if(line_nr<view->get_buffer()->get_line_count()) { if(line_nr<view->get_buffer()->get_line_count()) {
auto iter=view->get_buffer()->get_iter_at_line(line_nr); auto iter=view->get_buffer()->get_iter_at_line(line_nr);
auto end_line_iter=iter; auto end_line_iter=iter;
@ -713,11 +714,13 @@ void Window::set_menu_actions() {
if(notebook.get_current_page()!=-1 && notebook.get_current_view()==view) if(notebook.get_current_page()!=-1 && notebook.get_current_view()==view)
view->scroll_to(view->get_buffer()->get_insert(), 0.0, 1.0, 0.5); view->scroll_to(view->get_buffer()->get_insert(), 0.0, 1.0, 0.5);
} }
project.debug_update_stop(); Project::debug_update_stop();
} }
} }
} }
}); });
Project::debug_update_status("");
#endif #endif
menu.add_action("next_tab", [this]() { menu.add_action("next_tab", [this]() {

Loading…
Cancel
Save