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. 246
      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
project.h
project.cc
dispatcher.h
dispatcher.cc
../libclangmm/src/CodeCompleteResults.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_ */

246
src/project.cc

@ -4,83 +4,74 @@
#include "filesystem.h"
#include <fstream>
#include "menu.h"
#include "notebook.h"
#ifdef JUCI_ENABLE_DEBUG
#include "debug.h"
#endif
Project::Project() : notebook(Notebook::get()), compiling(false), debugging(false) {
debug_update_stop.connect([this](){
debug_stop_mutex.lock();
for(int c=0;c<notebook.size();c++) {
auto view=notebook.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++) {
auto view=notebook.get_view(c);
if(view->file_path==debug_stop.first) {
if(debug_stop.second.first-1<view->get_buffer()->get_line_count()) {
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;
}
}
if(notebook.get_current_page()!=-1)
notebook.get_current_view()->get_buffer()->place_cursor(notebook.get_current_view()->get_buffer()->get_insert()->get_iter());
debug_stop_mutex.unlock();
});
std::unordered_map<std::string, std::string> Project::run_arguments;
std::unordered_map<std::string, std::string> Project::debug_run_arguments;
std::atomic<bool> Project::compiling;
std::atomic<bool> Project::debugging;
std::pair<boost::filesystem::path, std::pair<int, int> > Project::debug_stop;
boost::filesystem::path Project::debug_last_stop_file_path;
std::unique_ptr<Gtk::Label> Project::debug_status_label;
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();
}
}
#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);
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;
}
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();
}
//Add debug stop source mark
for(int c=0;c<Notebook::get().size();c++) {
auto view=Notebook::get().get_view(c);
if(view->file_path==debug_stop.first) {
if(debug_stop.second.first-1<view->get_buffer()->get_line_count()) {
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;
}
debug_status_mutex.unlock();
});
}
if(Notebook::get().get_current_page()!=-1)
Notebook::get().get_current_view()->get_buffer()->place_cursor(Notebook::get().get_current_view()->get_buffer()->get_insert()->get_iter());
}
std::unique_ptr<Project::Language> Project::get_language() {
if(notebook.get_current_page()!=-1) {
auto language_id=notebook.get_current_view()->language->get_id();
if(Notebook::get().get_current_page()!=-1) {
auto language_id=Notebook::get().get_current_view()->language->get_id();
if(language_id=="markdown")
return std::unique_ptr<Project::Language>(new Project::Markdown());
if(language_id=="python")
@ -96,8 +87,8 @@ std::unique_ptr<Project::Language> Project::get_language() {
std::unique_ptr<CMake> Project::Clang::get_cmake() {
boost::filesystem::path path;
if(notebook.get_current_page()!=-1)
path=notebook.get_current_view()->file_path.parent_path();
if(Notebook::get().get_current_page()!=-1)
path=Notebook::get().get_current_view()->file_path.parent_path();
else
path=Directories::get().current_path;
if(path.empty())
@ -116,13 +107,13 @@ std::pair<std::string, std::string> Project::Clang::get_run_arguments() {
return {"", ""};
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;
if(run_arguments_it!=Project::get().run_arguments.end())
if(run_arguments_it!=run_arguments.end())
arguments=run_arguments_it->second;
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!="") {
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);
if(default_build_path.empty())
return;
Project::get().compiling=true;
compiling=true;
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) {
Project::get().compiling=false;
compiling=false;
});
}
@ -166,13 +157,13 @@ void Project::Clang::compile_and_run() {
if(default_build_path.empty())
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;
if(run_arguments_it!=Project::get().run_arguments.end())
if(run_arguments_it!=run_arguments.end())
arguments=run_arguments_it->second;
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()) {
Terminal::get().print("Could not find add_executable in the following paths:\n");
for(auto &path: cmake->paths)
@ -186,10 +177,10 @@ void Project::Clang::compile_and_run() {
arguments=filesystem::escape_argument(arguments);
}
Project::get().compiling=true;
compiling=true;
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){
Project::get().compiling=false;
compiling=false;
if(exit_status==EXIT_SUCCESS) {
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');
@ -205,13 +196,13 @@ std::pair<std::string, std::string> Project::Clang::debug_get_run_arguments() {
return {"", ""};
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;
if(run_arguments_it!=Project::get().debug_run_arguments.end())
if(run_arguments_it!=debug_run_arguments.end())
arguments=run_arguments_it->second;
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!="") {
auto project_path=cmake->project_path;
@ -242,13 +233,13 @@ void Project::Clang::debug_start() {
if(!CMake::create_debug_build(project_path))
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;
if(run_arguments_it!=Project::get().debug_run_arguments.end())
if(run_arguments_it!=debug_run_arguments.end())
run_arguments=run_arguments_it->second;
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()) {
Terminal::get().print("Could not find add_executable in the following paths:\n");
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> > >();
for(int c=0;c<notebook.size();c++) {
auto view=notebook.get_view(c);
for(int c=0;c<Notebook::get().size();c++) {
auto view=Notebook::get().get_view(c);
if(project_path==view->project_path) {
auto iter=view->get_buffer()->begin();
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().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)
Project::get().debugging=false;
debugging=false;
else {
debug_start_mutex.lock();
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');
}, [this](const std::string &status) {
auto &project=Project::get();
project.debug_status_mutex.lock();
project.debug_status=status;
project.debug_status_mutex.unlock();
project.debug_update_status();
dispatcher.add([this, status] {
debug_update_status(status);
});
}, [this](const boost::filesystem::path &file_path, int line_nr, int line_index) {
auto &project=Project::get();
project.debug_stop_mutex.lock();
project.debug_stop.first=file_path;
project.debug_stop.second.first=line_nr;
project.debug_stop.second.second=line_index;
project.debug_stop_mutex.unlock();
project.debug_update_stop();
dispatcher.add([this, file_path, line_nr, line_index] {
Project::debug_stop.first=file_path;
Project::debug_stop.second.first=line_nr;
Project::debug_stop.second.second=line_index;
debug_update_stop();
});
});
debug_start_mutex.unlock();
}
@ -309,35 +299,35 @@ void Project::Clang::debug_continue() {
}
void Project::Clang::debug_stop() {
if(Project::get().debugging)
if(debugging)
Debug::get().stop();
}
void Project::Clang::debug_kill() {
if(Project::get().debugging)
if(debugging)
Debug::get().kill();
}
void Project::Clang::debug_step_over() {
if(Project::get().debugging)
if(debugging)
Debug::get().step_over();
}
void Project::Clang::debug_step_into() {
if(Project::get().debugging)
if(debugging)
Debug::get().step_into();
}
void Project::Clang::debug_step_out() {
if(Project::get().debugging)
if(debugging)
Debug::get().step_out();
}
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 view=notebook.get_current_view();
auto view=Notebook::get().get_current_view();
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));
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) {
auto frame=rows->at(selected);
if(!frame.file_path.empty()) {
notebook.open(frame.file_path);
if(notebook.get_current_page()!=-1) {
auto view=notebook.get_current_view();
Notebook::get().open(frame.file_path);
if(Notebook::get().get_current_page()!=-1) {
auto view=Notebook::get().get_current_view();
Debug::get().select_frame(frame.index);
@ -374,7 +364,7 @@ void Project::Clang::debug_backtrace() {
while(g_main_context_pending(NULL))
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);
}
}
@ -384,10 +374,10 @@ void Project::Clang::debug_backtrace() {
}
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 view=notebook.get_current_view();
auto view=Notebook::get().get_current_view();
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));
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) {
auto variable=rows->at(selected);
if(!variable.file_path.empty()) {
notebook.open(variable.file_path);
if(notebook.get_current_page()!=-1) {
auto view=notebook.get_current_view();
Notebook::get().open(variable.file_path);
if(Notebook::get().get_current_page()!=-1) {
auto view=Notebook::get().get_current_view();
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))
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);
}
}
@ -430,8 +420,8 @@ void Project::Clang::debug_show_variables() {
debug_variable_tooltips.hide();
return;
}
if(notebook.get_current_page()!=-1) {
auto view=notebook.get_current_view();
if(Notebook::get().get_current_page()!=-1) {
auto view=Notebook::get().get_current_view();
debug_variable_tooltips.clear();
auto create_tooltip_buffer=[this, rows, view, 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) {
if(Project::get().debugging) {
if(debugging) {
auto command_return=Debug::get().run_command(command);
Terminal::get().async_print(command_return.first);
Terminal::get().async_print(command_return.second, true);
@ -498,7 +488,7 @@ void Project::Markdown::compile_and_run() {
}
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) {
boost::system::error_code 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() {
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().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');
});
}
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().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');
});
}
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__
Terminal::get().process("open \""+uri+"\"");
#else

41
src/project.h

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

59
src/terminal.cc

@ -7,9 +7,6 @@
#endif
Terminal::InProgress::InProgress(const std::string& start_msg): stop(false) {
waiting_print.connect([this](){
Terminal::get().async_print(line_nr-1, ".");
});
start(start_msg);
}
@ -24,8 +21,11 @@ void Terminal::InProgress::start(const std::string& msg) {
wait_thread=std::thread([this](){
size_t c=0;
while(!stop) {
if(c%100==0)
waiting_print();
if(c%100==0) {
dispatcher.add([this] {
Terminal::get().print(line_nr-1, ".");
});
}
std::this_thread::sleep_for(std::chrono::milliseconds(10));
c++;
}
@ -35,39 +35,24 @@ void Terminal::InProgress::start(const std::string& msg) {
void Terminal::InProgress::done(const std::string& msg) {
if(!stop) {
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) {
if(!stop) {
stop=true;
Terminal::get().async_print(line_nr-1, msg);
dispatcher.add([this, msg] {
Terminal::get().print(line_nr-1, msg);
});
}
}
Terminal::Terminal() {
bold_tag=get_buffer()->create_tag();
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) {
@ -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) {
async_print_strings_mutex.lock();
bool dispatch=true;
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();
dispatcher.add([this, message, bold] {
Terminal::get().print(message, bold);
});
}
bool Terminal::on_key_press_event(GdkEventKey *event) {

12
src/terminal.h

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

47
src/window.cc

@ -25,7 +25,11 @@ Window::Window() : notebook(Notebook::get()) {
JDEBUG("start");
set_title("juCi++");
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();
configure();
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);
info_and_status_hbox.pack_start(notebook.info, Gtk::PACK_SHRINK);
#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
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
info_and_status_hbox.pack_end(notebook.status, 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]() {
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());
if(run_arguments->second.empty())
return;
@ -517,7 +522,7 @@ void Window::set_menu_actions() {
};
label_it->update(0, "");
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();
}, 50);
auto entry_it=entry_box.entries.begin();
@ -528,23 +533,23 @@ void Window::set_menu_actions() {
entry_box.show();
});
menu.add_action("compile_and_run", [this]() {
if(Project::get().compiling)
if(Project::compiling)
return;
if(Config::get().window.save_on_compile_or_run)
notebook.save_project_files();
project_language=Project::get().get_language();
project_language=Project::get_language();
project_language->compile_and_run();
});
menu.add_action("compile", [this]() {
if(Project::get().compiling)
if(Project::compiling)
return;
if(Config::get().window.save_on_compile_or_run)
notebook.save_project_files();
project_language=Project::get().get_language();
project_language=Project::get_language();
project_language->compile();
});
@ -585,7 +590,7 @@ void Window::set_menu_actions() {
#ifdef JUCI_ENABLE_DEBUG
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());
if(run_arguments->second.empty())
return;
@ -598,7 +603,7 @@ void Window::set_menu_actions() {
};
label_it->update(0, "");
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();
}, 50);
auto entry_it=entry_box.entries.begin();
@ -609,7 +614,7 @@ void Window::set_menu_actions() {
entry_box.show();
});
menu.add_action("debug_start_continue", [this](){
if(Project::get().debugging) {
if(Project::debugging) {
project_language->debug_continue();
return;
}
@ -617,7 +622,7 @@ void Window::set_menu_actions() {
if(Config::get().window.save_on_compile_or_run)
notebook.save_project_files();
project_language=Project::get().get_language();
project_language=Project::get_language();
project_language->debug_start();
});
@ -687,18 +692,14 @@ void Window::set_menu_actions() {
}
});
menu.add_action("debug_goto_stop", [this](){
if(Project::get().debugging) {
auto &project=Project::get();
project.debug_stop_mutex.lock();
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(Project::debugging) {
if(!Project::debug_stop.first.empty()) {
notebook.open(Project::debug_stop.first);
if(notebook.get_current_page()!=-1) {
auto view=notebook.get_current_view();
int line_nr=debug_stop_copy.second.first-1;
int line_index=debug_stop_copy.second.second-1;
int line_nr=Project::debug_stop.second.first-1;
int line_index=Project::debug_stop.second.second-1;
if(line_nr<view->get_buffer()->get_line_count()) {
auto iter=view->get_buffer()->get_iter_at_line(line_nr);
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)
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
menu.add_action("next_tab", [this]() {

Loading…
Cancel
Save