Browse Source

Merge pull request #168 from eidheim/master

Fixes #6 and #97
merge-requests/365/head
Jørgen Lien Sellæg 10 years ago
parent
commit
688d1ea8c7
  1. 2
      src/CMakeLists.txt
  2. 76
      src/cmake.cc
  3. 7
      src/cmake.h
  4. 38
      src/dialogs.cc
  5. 15
      src/dialogs.h
  6. 22
      src/dialogs_unix.cc
  7. 303
      src/directories.cc
  8. 54
      src/directories.h
  9. 8
      src/entrybox.h
  10. 6
      src/files.h
  11. 19
      src/filesystem.cc
  12. 3
      src/filesystem.h
  13. 74
      src/notebook.cc
  14. 1
      src/notebook.h
  15. 157
      src/project.cc
  16. 55
      src/project.h
  17. 77
      src/project_build.cc
  18. 37
      src/project_build.h
  19. 31
      src/source.cc
  20. 10
      src/source.h
  21. 29
      src/source_clang.cc
  22. 8
      src/source_clang.h
  23. 194
      src/window.cc
  24. 3
      src/window.h

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
project_build.h
project_build.cc
dispatcher.h dispatcher.h
dispatcher.cc dispatcher.cc

76
src/cmake.cc

@ -5,8 +5,6 @@
#include "terminal.h" #include "terminal.h"
#include <boost/regex.hpp> #include <boost/regex.hpp>
std::unordered_set<std::string> CMake::debug_build_needed;
CMake::CMake(const boost::filesystem::path &path) { CMake::CMake(const boost::filesystem::path &path) {
const auto find_cmake_project=[this](const boost::filesystem::path &cmake_path) { const auto find_cmake_project=[this](const boost::filesystem::path &cmake_path) {
for(auto &line: filesystem::read_lines(cmake_path)) { for(auto &line: filesystem::read_lines(cmake_path)) {
@ -18,7 +16,7 @@ CMake::CMake(const boost::filesystem::path &path) {
return false; return false;
}; };
auto search_path=path; auto search_path=boost::filesystem::is_directory(path)?path:path.parent_path();
while(true) { while(true) {
auto search_cmake_path=search_path/"CMakeLists.txt"; auto search_cmake_path=search_path/"CMakeLists.txt";
if(boost::filesystem::exists(search_cmake_path)) if(boost::filesystem::exists(search_cmake_path))
@ -35,65 +33,13 @@ CMake::CMake(const boost::filesystem::path &path) {
} }
} }
boost::filesystem::path CMake::get_default_build_path(const boost::filesystem::path &project_path) { bool CMake::update_default_build(const boost::filesystem::path &default_build_path, bool force) {
boost::filesystem::path default_build_path=Config::get().project.default_build_path;
const std::string path_variable_project_directory_name="<project_directory_name>";
size_t pos=0;
auto default_build_path_string=default_build_path.string();
auto path_filename_string=project_path.filename().string();
while((pos=default_build_path_string.find(path_variable_project_directory_name, pos))!=std::string::npos) {
default_build_path_string.replace(pos, path_variable_project_directory_name.size(), path_filename_string);
pos+=path_filename_string.size();
}
if(pos!=0)
default_build_path=default_build_path_string;
if(default_build_path.is_relative())
default_build_path=project_path/default_build_path;
return default_build_path;
}
boost::filesystem::path CMake::get_debug_build_path(const boost::filesystem::path &project_path) {
boost::filesystem::path debug_build_path=Config::get().project.debug_build_path;
const std::string path_variable_project_directory_name="<project_directory_name>";
size_t pos=0;
auto debug_build_path_string=debug_build_path.string();
auto path_filename_string=project_path.filename().string();
while((pos=debug_build_path_string.find(path_variable_project_directory_name, pos))!=std::string::npos) {
debug_build_path_string.replace(pos, path_variable_project_directory_name.size(), path_filename_string);
pos+=path_filename_string.size();
}
if(pos!=0)
debug_build_path=debug_build_path_string;
const std::string path_variable_default_build_path="<default_build_path>";
pos=0;
debug_build_path_string=debug_build_path.string();
auto default_build_path=Config::get().project.default_build_path;
while((pos=debug_build_path_string.find(path_variable_default_build_path, pos))!=std::string::npos) {
debug_build_path_string.replace(pos, path_variable_default_build_path.size(), default_build_path);
pos+=default_build_path.size();
}
if(pos!=0)
debug_build_path=debug_build_path_string;
if(debug_build_path.is_relative())
debug_build_path=project_path/debug_build_path;
return debug_build_path;
}
bool CMake::create_default_build(const boost::filesystem::path &project_path, bool force) {
if(project_path.empty()) if(project_path.empty())
return false; return false;
if(!boost::filesystem::exists(project_path/"CMakeLists.txt")) if(!boost::filesystem::exists(project_path/"CMakeLists.txt"))
return false; return false;
auto default_build_path=get_default_build_path(project_path);
if(default_build_path.empty()) if(default_build_path.empty())
return false; return false;
if(!boost::filesystem::exists(default_build_path)) { if(!boost::filesystem::exists(default_build_path)) {
@ -108,8 +54,6 @@ bool CMake::create_default_build(const boost::filesystem::path &project_path, bo
if(!force && boost::filesystem::exists(default_build_path/"compile_commands.json")) if(!force && boost::filesystem::exists(default_build_path/"compile_commands.json"))
return true; return true;
debug_build_needed.emplace(project_path.string());
auto compile_commands_path=default_build_path/"compile_commands.json"; auto compile_commands_path=default_build_path/"compile_commands.json";
Dialog::Message message("Creating/updating default build"); Dialog::Message message("Creating/updating default build");
auto exit_status=Terminal::get().process(Config::get().project.cmake_command+" "+ auto exit_status=Terminal::get().process(Config::get().project.cmake_command+" "+
@ -135,14 +79,13 @@ bool CMake::create_default_build(const boost::filesystem::path &project_path, bo
return false; return false;
} }
bool CMake::create_debug_build(const boost::filesystem::path &project_path) { bool CMake::update_debug_build(const boost::filesystem::path &debug_build_path, bool force) {
if(project_path.empty()) if(project_path.empty())
return false; return false;
if(!boost::filesystem::exists(project_path/"CMakeLists.txt")) if(!boost::filesystem::exists(project_path/"CMakeLists.txt"))
return false; return false;
auto debug_build_path=get_debug_build_path(project_path);
if(debug_build_path.empty()) if(debug_build_path.empty())
return false; return false;
if(!boost::filesystem::exists(debug_build_path)) { if(!boost::filesystem::exists(debug_build_path)) {
@ -154,11 +97,8 @@ bool CMake::create_debug_build(const boost::filesystem::path &project_path) {
} }
} }
if(boost::filesystem::exists(debug_build_path/"CMakeCache.txt")) { if(!force && boost::filesystem::exists(debug_build_path/"CMakeCache.txt"))
auto it=debug_build_needed.find(project_path.string()); return true;
if(it==debug_build_needed.end())
return true;
}
std::unique_ptr<Dialog::Message> message; std::unique_ptr<Dialog::Message> message;
message=std::unique_ptr<Dialog::Message>(new Dialog::Message("Creating/updating debug build")); message=std::unique_ptr<Dialog::Message>(new Dialog::Message("Creating/updating debug build"));
@ -166,12 +106,8 @@ bool CMake::create_debug_build(const boost::filesystem::path &project_path) {
filesystem::escape_argument(project_path)+" -DCMAKE_BUILD_TYPE=Debug", debug_build_path); filesystem::escape_argument(project_path)+" -DCMAKE_BUILD_TYPE=Debug", debug_build_path);
if(message) if(message)
message->hide(); message->hide();
if(exit_status==EXIT_SUCCESS) { if(exit_status==EXIT_SUCCESS)
auto it=debug_build_needed.find(project_path.string());
if(it!=debug_build_needed.end())
debug_build_needed.erase(it);
return true; return true;
}
return false; return false;
} }

7
src/cmake.h

@ -11,10 +11,8 @@ public:
boost::filesystem::path project_path; boost::filesystem::path project_path;
std::vector<boost::filesystem::path> paths; std::vector<boost::filesystem::path> paths;
static boost::filesystem::path get_default_build_path(const boost::filesystem::path &project_path); bool update_default_build(const boost::filesystem::path &default_build_path, bool force=false);
static boost::filesystem::path get_debug_build_path(const boost::filesystem::path &project_path); bool update_debug_build(const boost::filesystem::path &debug_build_path, bool force=false);
static bool create_default_build(const boost::filesystem::path &project_path, bool force=false);
static bool create_debug_build(const boost::filesystem::path &project_path);
boost::filesystem::path get_executable(const boost::filesystem::path &file_path); boost::filesystem::path get_executable(const boost::filesystem::path &file_path);
@ -31,6 +29,5 @@ private:
void parse(); void parse();
std::vector<std::string> get_function_parameters(std::string &data); std::vector<std::string> get_function_parameters(std::string &data);
bool parsed=false; bool parsed=false;
static std::unordered_set<std::string> debug_build_needed;
}; };
#endif //JUCI_CMAKE_H_ #endif //JUCI_CMAKE_H_

38
src/dialogs.cc

@ -1,6 +1,4 @@
#include "dialogs.h" #include "dialogs.h"
#include "window.h"
#include "notebook.h"
#include <cmath> #include <cmath>
namespace sigc { namespace sigc {
@ -18,7 +16,10 @@ namespace sigc {
} }
Dialog::Message::Message(const std::string &text): Gtk::MessageDialog(text, false, Gtk::MessageType::MESSAGE_INFO, Gtk::ButtonsType::BUTTONS_NONE, true) { Dialog::Message::Message(const std::string &text): Gtk::MessageDialog(text, false, Gtk::MessageType::MESSAGE_INFO, Gtk::ButtonsType::BUTTONS_NONE, true) {
set_transient_for(::Window::get()); auto g_application=g_application_get_default();
auto gio_application=Glib::wrap(g_application, true);
auto application=Glib::RefPtr<Gtk::Application>::cast_static(gio_application);
set_transient_for(*application->get_active_window());
set_position(Gtk::WindowPosition::WIN_POS_CENTER_ON_PARENT); set_position(Gtk::WindowPosition::WIN_POS_CENTER_ON_PARENT);
show_now(); show_now();
@ -27,25 +28,28 @@ Dialog::Message::Message(const std::string &text): Gtk::MessageDialog(text, fals
g_main_context_iteration(NULL, false); g_main_context_iteration(NULL, false);
} }
std::string Dialog::gtk_dialog(const std::string &title, std::string Dialog::gtk_dialog(const boost::filesystem::path &path, const std::string &title,
const std::vector<std::pair<std::string, Gtk::ResponseType>> &buttons, const std::vector<std::pair<std::string, Gtk::ResponseType>> &buttons,
Gtk::FileChooserAction gtk_options, Gtk::FileChooserAction gtk_options) {
const std::string &file_name) {
Gtk::FileChooserDialog dialog(title, gtk_options); Gtk::FileChooserDialog dialog(title, gtk_options);
dialog.set_transient_for(Window::get()); auto g_application=g_application_get_default();
auto gio_application=Glib::wrap(g_application, true);
auto current_path=Notebook::get().get_current_folder(); auto application=Glib::RefPtr<Gtk::Application>::cast_static(gio_application);
boost::system::error_code ec; dialog.set_transient_for(*application->get_active_window());
if(current_path.empty())
current_path=boost::filesystem::current_path(ec);
if(!ec)
gtk_file_chooser_set_current_folder((GtkFileChooser*)dialog.gobj(), current_path.string().c_str());
if (!file_name.empty())
gtk_file_chooser_set_filename((GtkFileChooser*)dialog.gobj(), file_name.c_str());
dialog.set_position(Gtk::WindowPosition::WIN_POS_CENTER_ON_PARENT); dialog.set_position(Gtk::WindowPosition::WIN_POS_CENTER_ON_PARENT);
if(title=="Save File As")
gtk_file_chooser_set_filename(reinterpret_cast<GtkFileChooser*>(dialog.gobj()), path.string().c_str());
else if(!path.empty())
gtk_file_chooser_set_current_folder(reinterpret_cast<GtkFileChooser*>(dialog.gobj()), path.string().c_str());
else {
boost::system::error_code ec;
auto current_path=boost::filesystem::current_path(ec);
if(!ec)
gtk_file_chooser_set_current_folder(reinterpret_cast<GtkFileChooser*>(dialog.gobj()), current_path.string().c_str());
}
for (auto &button : buttons) for (auto &button : buttons)
dialog.add_button(button.first, button.second); dialog.add_button(button.first, button.second);
return dialog.run() == Gtk::RESPONSE_OK ? dialog.get_filename() : ""; return dialog.run() == Gtk::RESPONSE_OK ? dialog.get_filename() : "";

15
src/dialogs.h

@ -7,11 +7,11 @@
class Dialog { class Dialog {
public: public:
static std::string open_folder(); static std::string open_folder(const boost::filesystem::path &path);
static std::string open_file(); static std::string open_file(const boost::filesystem::path &path);
static std::string new_file(); static std::string new_file(const boost::filesystem::path &path);
static std::string new_folder(); static std::string new_folder(const boost::filesystem::path &path);
static std::string save_file_as(const boost::filesystem::path &file_path); static std::string save_file_as(const boost::filesystem::path &path);
class Message : public Gtk::MessageDialog { class Message : public Gtk::MessageDialog {
public: public:
@ -19,10 +19,9 @@ public:
}; };
private: private:
static std::string gtk_dialog(const std::string &title, static std::string gtk_dialog(const boost::filesystem::path &path, const std::string &title,
const std::vector<std::pair<std::string, Gtk::ResponseType>> &buttons, const std::vector<std::pair<std::string, Gtk::ResponseType>> &buttons,
Gtk::FileChooserAction gtk_options, Gtk::FileChooserAction gtk_options);
const std::string &file_name = "");
}; };
#endif //JUCI_DIALOG_H_ #endif //JUCI_DIALOG_H_

22
src/dialogs_unix.cc

@ -1,32 +1,32 @@
#include "dialogs.h" #include "dialogs.h"
std::string Dialog::open_folder() { std::string Dialog::open_folder(const boost::filesystem::path &path) {
return gtk_dialog("Open Folder", return gtk_dialog(path, "Open Folder",
{std::make_pair("Cancel", Gtk::RESPONSE_CANCEL),std::make_pair("Open", Gtk::RESPONSE_OK)}, {std::make_pair("Cancel", Gtk::RESPONSE_CANCEL),std::make_pair("Open", Gtk::RESPONSE_OK)},
Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER); Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER);
} }
std::string Dialog::new_file() { std::string Dialog::new_file(const boost::filesystem::path &path) {
return gtk_dialog("New File", return gtk_dialog(path, "New File",
{std::make_pair("Cancel", Gtk::RESPONSE_CANCEL), std::make_pair("Save", Gtk::RESPONSE_OK)}, {std::make_pair("Cancel", Gtk::RESPONSE_CANCEL), std::make_pair("Save", Gtk::RESPONSE_OK)},
Gtk::FILE_CHOOSER_ACTION_SAVE); Gtk::FILE_CHOOSER_ACTION_SAVE);
} }
std::string Dialog::new_folder() { std::string Dialog::new_folder(const boost::filesystem::path &path) {
return gtk_dialog("New Folder", return gtk_dialog(path, "New Folder",
{std::make_pair("Cancel", Gtk::RESPONSE_CANCEL),std::make_pair("Create", Gtk::RESPONSE_OK)}, {std::make_pair("Cancel", Gtk::RESPONSE_CANCEL),std::make_pair("Create", Gtk::RESPONSE_OK)},
Gtk::FILE_CHOOSER_ACTION_CREATE_FOLDER); Gtk::FILE_CHOOSER_ACTION_CREATE_FOLDER);
} }
std::string Dialog::open_file() { std::string Dialog::open_file(const boost::filesystem::path &path) {
return gtk_dialog("Open File", return gtk_dialog(path, "Open File",
{std::make_pair("Cancel", Gtk::RESPONSE_CANCEL),std::make_pair("Select", Gtk::RESPONSE_OK)}, {std::make_pair("Cancel", Gtk::RESPONSE_CANCEL),std::make_pair("Select", Gtk::RESPONSE_OK)},
Gtk::FILE_CHOOSER_ACTION_OPEN); Gtk::FILE_CHOOSER_ACTION_OPEN);
} }
std::string Dialog::save_file_as(const boost::filesystem::path &file_path) { std::string Dialog::save_file_as(const boost::filesystem::path &path) {
return gtk_dialog("Save File As", return gtk_dialog(path, "Save File As",
{std::make_pair("Cancel", Gtk::RESPONSE_CANCEL),std::make_pair("Save", Gtk::RESPONSE_OK)}, {std::make_pair("Cancel", Gtk::RESPONSE_CANCEL),std::make_pair("Save", Gtk::RESPONSE_OK)},
Gtk::FILE_CHOOSER_ACTION_SAVE, file_path.string()); Gtk::FILE_CHOOSER_ACTION_SAVE);
} }

303
src/directories.cc

@ -3,6 +3,10 @@
#include <algorithm> #include <algorithm>
#include <unordered_set> #include <unordered_set>
#include "source.h" #include "source.h"
#include "terminal.h"
#include "notebook.h"
#include "filesystem.h"
#include "entrybox.h"
#include <iostream> //TODO: remove #include <iostream> //TODO: remove
using namespace std; //TODO: remove using namespace std; //TODO: remove
@ -21,10 +25,100 @@ namespace sigc {
#endif #endif
} }
bool Directories::TreeStore::row_drop_possible_vfunc(const Gtk::TreeModel::Path &path, const Gtk::SelectionData &selection_data) const {
return true;
}
bool Directories::TreeStore::drag_data_received_vfunc(const TreeModel::Path &path, const Gtk::SelectionData &selection_data) {
auto &directories=Directories::get();
auto get_target_folder=[this, &directories](const TreeModel::Path &path) {
if(path.size()==1)
return directories.path;
else {
auto it=get_iter(path);
if(it) {
auto prev_path=path;
prev_path.up();
it=get_iter(prev_path);
if(it)
return it->get_value(directories.column_record.path);
}
else {
auto prev_path=path;
prev_path.up();
if(prev_path.size()==1)
return directories.path;
else {
prev_path.up();
it=get_iter(prev_path);
if(it)
return it->get_value(directories.column_record.path);
}
}
}
return boost::filesystem::path();
};
auto it=directories.get_selection()->get_selected();
if(it) {
auto source_path=it->get_value(directories.column_record.path);
auto target_path=get_target_folder(path);
target_path/=source_path.filename();
if(source_path==target_path)
return false;
if(boost::filesystem::exists(target_path)) {
Terminal::get().print("Error: could not move file: "+target_path.string()+" already exists\n", true);
return false;
}
bool is_directory=boost::filesystem::is_directory(source_path);
boost::system::error_code ec;
boost::filesystem::rename(source_path, target_path, ec);
if(ec) {
Terminal::get().print("Error: could not move file: "+ec.message()+'\n', true);
return false;
}
for(int c=0;c<Notebook::get().size();c++) {
auto view=Notebook::get().get_view(c);
if(is_directory) {
if(filesystem::file_in_path(view->file_path, source_path)) {
auto file_it=view->file_path.begin();
for(auto source_it=source_path.begin();source_it!=source_path.end();source_it++)
file_it++;
auto new_file_path=target_path;
for(;file_it!=view->file_path.end();file_it++)
new_file_path/=*file_it;
view->file_path=new_file_path;
}
}
if(view->file_path==source_path) {
view->file_path=target_path;
break;
}
}
Directories::get().update();
directories.select(target_path);
}
return false;
}
bool Directories::TreeStore::drag_data_delete_vfunc (const Gtk::TreeModel::Path &path) {
return false;
}
Directories::Directories() : Gtk::TreeView(), stop_update_thread(false) { Directories::Directories() : Gtk::TreeView(), stop_update_thread(false) {
this->set_enable_tree_lines(true); this->set_enable_tree_lines(true);
tree_store = Gtk::TreeStore::create(column_record); tree_store = TreeStore::create();
tree_store->set_column_types(column_record);
set_model(tree_store); set_model(tree_store);
append_column("", column_record.name); append_column("", column_record.name);
auto renderer=dynamic_cast<Gtk::CellRendererText*>(get_column(0)->get_first_cell()); auto renderer=dynamic_cast<Gtk::CellRendererText*>(get_column(0)->get_first_cell());
@ -34,7 +128,7 @@ Directories::Directories() : Gtk::TreeView(), stop_update_thread(false) {
set_enable_search(true); //TODO: why does this not work in OS X? set_enable_search(true); //TODO: why does this not work in OS X?
set_search_column(column_record.name); set_search_column(column_record.name);
signal_row_activated().connect([this](const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column){ signal_row_activated().connect([this](const Gtk::TreeModel::Path &path, Gtk::TreeViewColumn *column){
auto iter = tree_store->get_iter(path); auto iter = tree_store->get_iter(path);
if (iter) { if (iter) {
auto filesystem_path=iter->get_value(column_record.path); auto filesystem_path=iter->get_value(column_record.path);
@ -49,7 +143,7 @@ Directories::Directories() : Gtk::TreeView(), stop_update_thread(false) {
} }
}); });
signal_test_expand_row().connect([this](const Gtk::TreeModel::iterator& iter, const Gtk::TreeModel::Path& path){ signal_test_expand_row().connect([this](const Gtk::TreeModel::iterator &iter, const Gtk::TreeModel::Path &path){
if(iter->children().begin()->get_value(column_record.path)=="") { if(iter->children().begin()->get_value(column_record.path)=="") {
update_mutex.lock(); update_mutex.lock();
add_path(iter->get_value(column_record.path), *iter); add_path(iter->get_value(column_record.path), *iter);
@ -57,7 +151,7 @@ Directories::Directories() : Gtk::TreeView(), stop_update_thread(false) {
} }
return false; return false;
}); });
signal_row_collapsed().connect([this](const Gtk::TreeModel::iterator& iter, const Gtk::TreeModel::Path& path){ signal_row_collapsed().connect([this](const Gtk::TreeModel::iterator &iter, const Gtk::TreeModel::Path &path){
update_mutex.lock(); update_mutex.lock();
auto directory_str=iter->get_value(column_record.path).string(); auto directory_str=iter->get_value(column_record.path).string();
for(auto it=last_write_times.begin();it!=last_write_times.end();) { for(auto it=last_write_times.begin();it!=last_write_times.end();) {
@ -84,34 +178,127 @@ Directories::Directories() : Gtk::TreeView(), stop_update_thread(false) {
while(!stop_update_thread) { while(!stop_update_thread) {
std::this_thread::sleep_for(std::chrono::milliseconds(1000)); std::this_thread::sleep_for(std::chrono::milliseconds(1000));
update_mutex.lock(); update_mutex.lock();
if(update_paths.size()==0) { for(auto it=last_write_times.begin();it!=last_write_times.end();) {
for(auto it=last_write_times.begin();it!=last_write_times.end();) { boost::system::error_code ec;
boost::system::error_code ec; auto last_write_time=boost::filesystem::last_write_time(it->first, ec);
auto last_write_time=boost::filesystem::last_write_time(it->first, ec); auto now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
if(!ec) { if(!ec) {
if(it->second.second<last_write_time) { if(last_write_time!=now && it->second.second<last_write_time) {
update_paths.emplace_back(it->first); auto path=std::make_shared<std::string>(it->first);
} dispatcher.post([this, path, last_write_time] {
it++; update_mutex.lock();
auto it=last_write_times.find(*path);
if(it!=last_write_times.end())
add_path(*path, it->second.first, last_write_time);
update_mutex.unlock();
});
} }
else it++;
it=last_write_times.erase(it);
} }
if(update_paths.size()>0) { else
dispatcher.post([this] { it=last_write_times.erase(it);
update_mutex.lock(); }
for(auto &path: update_paths) { update_mutex.unlock();
if(last_write_times.count(path)>0) }
add_path(path, last_write_times.at(path).first); });
enable_model_drag_source();
enable_model_drag_dest();
menu_item_rename.set_label("Rename");
menu_item_rename.signal_activate().connect([this] {
if(menu_popup_row_path.empty())
return;
EntryBox::get().clear();
auto source_path=std::make_shared<boost::filesystem::path>(menu_popup_row_path);
EntryBox::get().entries.emplace_back(menu_popup_row_path.filename().string(), [this, source_path](const std::string &content){
bool is_directory=boost::filesystem::is_directory(*source_path);
boost::system::error_code ec;
auto target_path=source_path->parent_path()/content;
boost::filesystem::rename(*source_path, target_path, ec);
if(ec)
Terminal::get().print("Error: could not rename "+source_path->string()+": "+ec.message()+'\n');
else {
update();
select(target_path);
for(int c=0;c<Notebook::get().size();c++) {
auto view=Notebook::get().get_view(c);
if(is_directory) {
if(filesystem::file_in_path(view->file_path, *source_path)) {
auto file_it=view->file_path.begin();
for(auto source_it=source_path->begin();source_it!=source_path->end();source_it++)
file_it++;
auto new_file_path=target_path;
for(;file_it!=view->file_path.end();file_it++)
new_file_path/=*file_it;
view->file_path=new_file_path;
} }
update_paths.clear(); }
update_mutex.unlock(); else if(view->file_path==*source_path) {
}); view->file_path=target_path;
g_signal_emit_by_name(view->get_buffer()->gobj(), "modified_changed");
std::string old_language_id;
if(view->language)
old_language_id=view->language->get_id();
view->language=Source::guess_language(target_path);
std::string new_language_id;
if(view->language)
new_language_id=view->language->get_id();
if(new_language_id!=old_language_id)
Terminal::get().print("Warning: language for "+target_path.string()+" has changed. Please reopen the file\n");
}
}
EntryBox::get().hide();
}
});
auto entry_it=EntryBox::get().entries.begin();
entry_it->set_placeholder_text("Filename");
EntryBox::get().buttons.emplace_back("Rename file", [this, entry_it](){
entry_it->activate();
});
EntryBox::get().show();
});
menu.append(menu_item_rename);
menu_item_delete.set_label("Delete");
menu_item_delete.signal_activate().connect([this] {
if(menu_popup_row_path.empty())
return;
Gtk::MessageDialog dialog((Gtk::Window&)(*get_toplevel()), "Delete!", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO);
dialog.set_default_response(Gtk::RESPONSE_NO);
dialog.set_secondary_text("Are you sure you want to delete "+menu_popup_row_path.string()+"?");
int result = dialog.run();
if(result==Gtk::RESPONSE_YES) {
bool is_directory=boost::filesystem::is_directory(menu_popup_row_path);
boost::system::error_code ec;
boost::filesystem::remove_all(menu_popup_row_path, ec);
if(ec)
Terminal::get().print("Error: could not delete "+menu_popup_row_path.string()+": "+ec.message()+"\n", true);
else {
update();
for(int c=0;c<Notebook::get().size();c++) {
auto view=Notebook::get().get_view(c);
if(is_directory) {
if(filesystem::file_in_path(view->file_path, menu_popup_row_path))
view->get_buffer()->set_modified();
}
else if(view->file_path==menu_popup_row_path)
view->get_buffer()->set_modified();
} }
} }
update_mutex.unlock();
} }
}); });
menu.append(menu_item_delete);
menu.show_all();
menu.accelerate(*this);
} }
Directories::~Directories() { Directories::~Directories() {
@ -120,7 +307,7 @@ Directories::~Directories() {
dispatcher.disconnect(); dispatcher.disconnect();
} }
void Directories::open(const boost::filesystem::path& dir_path) { void Directories::open(const boost::filesystem::path &dir_path) {
JDEBUG("start"); JDEBUG("start");
if(dir_path.empty()) if(dir_path.empty())
return; return;
@ -128,29 +315,23 @@ void Directories::open(const boost::filesystem::path& dir_path) {
tree_store->clear(); tree_store->clear();
update_mutex.lock(); update_mutex.lock();
last_write_times.clear(); last_write_times.clear();
update_paths.clear();
update_mutex.unlock(); update_mutex.unlock();
cmake=std::unique_ptr<CMake>(new CMake(dir_path));
CMake::create_default_build(cmake->project_path); //TODO: report that set_title does not handle '_' correctly?
auto project=cmake->get_functions_parameters("project"); auto title=dir_path.filename().string();
if(project.size()>0 && project[0].second.size()>0) { size_t pos=0;
auto title=project[0].second[0]; while((pos=title.find('_', pos))!=std::string::npos) {
//TODO: report that set_title does not handle '_' correctly? title.replace(pos, 1, "__");
size_t pos=0; pos+=2;
while((pos=title.find('_', pos))!=std::string::npos) {
title.replace(pos, 1, "__");
pos+=2;
}
get_column(0)->set_title(title);
} }
else get_column(0)->set_title(title);
get_column(0)->set_title("");
update_mutex.lock(); update_mutex.lock();
add_path(dir_path, Gtk::TreeModel::Row()); add_path(dir_path, Gtk::TreeModel::Row());
update_mutex.unlock(); update_mutex.unlock();
current_path=dir_path; path=dir_path;
JDEBUG("end"); JDEBUG("end");
} }
@ -165,28 +346,28 @@ void Directories::update() {
JDEBUG("end"); JDEBUG("end");
} }
void Directories::select(const boost::filesystem::path &path) { void Directories::select(const boost::filesystem::path &select_path) {
JDEBUG("start"); JDEBUG("start");
if(current_path=="") if(path=="")
return; return;
if(path.generic_string().substr(0, current_path.generic_string().size()+1)!=current_path.generic_string()+'/') if(select_path.generic_string().substr(0, path.generic_string().size()+1)!=path.generic_string()+'/')
return; return;
std::list<boost::filesystem::path> paths; std::list<boost::filesystem::path> paths;
boost::filesystem::path parent_path; boost::filesystem::path parent_path;
if(boost::filesystem::is_directory(path)) if(boost::filesystem::is_directory(select_path))
parent_path=path; parent_path=select_path;
else else
parent_path=path.parent_path(); parent_path=select_path.parent_path();
paths.emplace_front(parent_path); paths.emplace_front(parent_path);
while(parent_path!=current_path) { while(parent_path!=path) {
parent_path=parent_path.parent_path(); parent_path=parent_path.parent_path();
paths.emplace_front(parent_path); paths.emplace_front(parent_path);
} }
for(auto &a_path: paths) { for(auto &a_path: paths) {
tree_store->foreach_iter([this, &a_path](const Gtk::TreeModel::iterator& iter){ tree_store->foreach_iter([this, &a_path](const Gtk::TreeModel::iterator &iter){
if(iter->get_value(column_record.path)==a_path) { if(iter->get_value(column_record.path)==a_path) {
update_mutex.lock(); update_mutex.lock();
add_path(a_path, *iter); add_path(a_path, *iter);
@ -197,8 +378,8 @@ void Directories::select(const boost::filesystem::path &path) {
}); });
} }
tree_store->foreach_iter([this, &path](const Gtk::TreeModel::iterator& iter){ tree_store->foreach_iter([this, &select_path](const Gtk::TreeModel::iterator &iter){
if(iter->get_value(column_record.path)==path) { if(iter->get_value(column_record.path)==select_path) {
auto tree_path=Gtk::TreePath(iter); auto tree_path=Gtk::TreePath(iter);
expand_to_path(tree_path); expand_to_path(tree_path);
set_cursor(tree_path); set_cursor(tree_path);
@ -209,9 +390,23 @@ void Directories::select(const boost::filesystem::path &path) {
JDEBUG("end"); JDEBUG("end");
} }
void Directories::add_path(const boost::filesystem::path& dir_path, const Gtk::TreeModel::Row &parent) { bool Directories::on_button_press_event(GdkEventButton* event) {
if(event->type==GDK_BUTTON_PRESS && event->button==GDK_BUTTON_SECONDARY) {
Gtk::TreeModel::Path path;
if(get_path_at_pos(static_cast<int>(event->x), static_cast<int>(event->y), path)) {
menu_popup_row_path=get_model()->get_iter(path)->get_value(column_record.path);
menu.popup(event->button, event->time);
return true;
}
}
return Gtk::TreeView::on_button_press_event(event);
}
void Directories::add_path(const boost::filesystem::path &dir_path, const Gtk::TreeModel::Row &parent, time_t last_write_time) {
boost::system::error_code ec; boost::system::error_code ec;
auto last_write_time=boost::filesystem::last_write_time(dir_path, ec); if(last_write_time==0)
last_write_time=boost::filesystem::last_write_time(dir_path, ec);
if(ec) if(ec)
return; return;
last_write_times[dir_path.string()]={parent, last_write_time}; last_write_times[dir_path.string()]={parent, last_write_time};

54
src/directories.h

@ -5,26 +5,38 @@
#include <vector> #include <vector>
#include <string> #include <string>
#include "boost/filesystem.hpp" #include "boost/filesystem.hpp"
#include "cmake.h"
#include <thread> #include <thread>
#include <mutex> #include <mutex>
#include <atomic> #include <atomic>
#include <unordered_map>
#include "dispatcher.h" #include "dispatcher.h"
class Directories : public Gtk::TreeView { class Directories : public Gtk::TreeView {
public: public:
class ColumnRecord : public Gtk::TreeModel::ColumnRecord { class TreeStore : public Gtk::TreeStore {
protected:
TreeStore() {}
bool row_drop_possible_vfunc(const Gtk::TreeModel::Path &path, const Gtk::SelectionData &selection_data) const override;
bool drag_data_received_vfunc(const TreeModel::Path &path, const Gtk::SelectionData &selection_data) override;
bool drag_data_delete_vfunc (const Gtk::TreeModel::Path &path) override;
public: public:
ColumnRecord() { class ColumnRecord : public Gtk::TreeModel::ColumnRecord {
add(id); public:
add(name); ColumnRecord() {
add(path); add(id);
add(color); add(name);
} add(path);
Gtk::TreeModelColumn<std::string> id; add(color);
Gtk::TreeModelColumn<std::string> name; }
Gtk::TreeModelColumn<boost::filesystem::path> path; Gtk::TreeModelColumn<std::string> id;
Gtk::TreeModelColumn<Gdk::RGBA> color; Gtk::TreeModelColumn<std::string> name;
Gtk::TreeModelColumn<boost::filesystem::path> path;
Gtk::TreeModelColumn<Gdk::RGBA> color;
};
static Glib::RefPtr<TreeStore> create() {return Glib::RefPtr<TreeStore>(new TreeStore());}
}; };
private: private:
@ -35,25 +47,31 @@ public:
return singleton; return singleton;
} }
~Directories(); ~Directories();
void open(const boost::filesystem::path& dir_path=""); void open(const boost::filesystem::path &dir_path="");
void update(); void update();
void select(const boost::filesystem::path &path); void select(const boost::filesystem::path &path);
std::function<void(const boost::filesystem::path &path)> on_row_activated; std::function<void(const boost::filesystem::path &path)> on_row_activated;
std::unique_ptr<CMake> cmake; boost::filesystem::path path;
boost::filesystem::path current_path;
protected:
bool on_button_press_event(GdkEventButton *event) override;
private: private:
void add_path(const boost::filesystem::path& dir_path, const Gtk::TreeModel::Row &row); void add_path(const boost::filesystem::path &dir_path, const Gtk::TreeModel::Row &row, time_t last_write_time=0);
Glib::RefPtr<Gtk::TreeStore> tree_store; Glib::RefPtr<Gtk::TreeStore> tree_store;
ColumnRecord column_record; TreeStore::ColumnRecord column_record;
std::unordered_map<std::string, std::pair<Gtk::TreeModel::Row, std::time_t> > last_write_times; std::unordered_map<std::string, std::pair<Gtk::TreeModel::Row, std::time_t> > last_write_times;
std::mutex update_mutex; std::mutex update_mutex;
std::thread update_thread; std::thread update_thread;
std::atomic<bool> stop_update_thread; std::atomic<bool> stop_update_thread;
Dispatcher dispatcher; Dispatcher dispatcher;
std::vector<std::string> update_paths;
Gtk::Menu menu;
Gtk::MenuItem menu_item_rename;
Gtk::MenuItem menu_item_delete;
boost::filesystem::path menu_popup_row_path;
}; };
#endif // JUCI_DIRECTORIES_H_ #endif // JUCI_DIRECTORIES_H_

8
src/entrybox.h

@ -33,8 +33,14 @@ public:
std::function<void(int state, const std::string& message)> update; std::function<void(int state, const std::string& message)> update;
}; };
public: private:
EntryBox(); EntryBox();
public:
static EntryBox &get() {
static EntryBox singleton;
return singleton;
}
Gtk::Box upper_box; Gtk::Box upper_box;
Gtk::Box lower_box; Gtk::Box lower_box;
void clear(); void clear();

6
src/files.h

@ -8,8 +8,8 @@ const std::string configjson =
"{\n" "{\n"
" \"version\": \""+std::string(JUCI_VERSION)+"\",\n" " \"version\": \""+std::string(JUCI_VERSION)+"\",\n"
" \"default_window_size\": {\n" " \"default_window_size\": {\n"
" \"width\": 600,\n" " \"width\": 800,\n"
" \"height\": 400\n" " \"height\": 600\n"
" },\n" " },\n"
" \"terminal_history_size\": 1000,\n" " \"terminal_history_size\": 1000,\n"
" \"gtk_theme\": {\n" " \"gtk_theme\": {\n"
@ -130,7 +130,7 @@ const std::string configjson =
" \"cmake_command\": \"cmake\",\n" " \"cmake_command\": \"cmake\",\n"
#endif #endif
" \"make_command\": \"cmake --build .\",\n" " \"make_command\": \"cmake --build .\",\n"
" \"save_on_compile_or_run\": false\n" " \"save_on_compile_or_run\": true\n"
" },\n" " },\n"
" \"documentation_searches\": {\n" " \"documentation_searches\": {\n"
" \"clang\": {\n" " \"clang\": {\n"

19
src/filesystem.cc

@ -1,6 +1,7 @@
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <algorithm>
#include "filesystem.h" #include "filesystem.h"
#include "logging.h" #include "logging.h"
@ -161,3 +162,21 @@ std::string filesystem::unescape(const std::string &argument) {
} }
return escaped; return escaped;
} }
bool filesystem::file_in_path(const boost::filesystem::path &file_path, const boost::filesystem::path &path) {
if(std::distance(file_path.begin(), file_path.end())<std::distance(path.begin(), path.end()))
return false;
return std::equal(path.begin(), path.end(), file_path.begin());
}
boost::filesystem::path filesystem::find_file_in_path_parents(const std::string &file_name, const boost::filesystem::path &path) {
auto current_path=path;
while(true) {
auto test_path=current_path/file_name;
if(boost::filesystem::exists(test_path))
return test_path;
if(current_path==current_path.root_directory())
return boost::filesystem::path();
current_path=current_path.parent_path();
}
}

3
src/filesystem.h

@ -28,5 +28,8 @@ public:
static std::string escape_argument(const std::string &argument); static std::string escape_argument(const std::string &argument);
static std::string escape_argument(const boost::filesystem::path &argument) { return escape_argument(argument.string()); }; static std::string escape_argument(const boost::filesystem::path &argument) { return escape_argument(argument.string()); };
static std::string unescape(const std::string &argument); static std::string unescape(const std::string &argument);
static bool file_in_path(const boost::filesystem::path &file_path, const boost::filesystem::path &path);
static boost::filesystem::path find_file_in_path_parents(const std::string &file_name, const boost::filesystem::path &path);
}; };
#endif // JUCI_FILESYSTEM_H_ #endif // JUCI_FILESYSTEM_H_

74
src/notebook.cc

@ -4,7 +4,7 @@
#include "logging.h" #include "logging.h"
#include <fstream> #include <fstream>
#include <regex> #include <regex>
#include "cmake.h" #include "project.h"
#include "filesystem.h" #include "filesystem.h"
#if GTKSOURCEVIEWMM_MAJOR_VERSION > 2 & GTKSOURCEVIEWMM_MINOR_VERSION > 17 #if GTKSOURCEVIEWMM_MAJOR_VERSION > 2 & GTKSOURCEVIEWMM_MINOR_VERSION > 17
@ -97,24 +97,10 @@ void Notebook::open(const boost::filesystem::path &file_path) {
} }
auto language=Source::guess_language(file_path); auto language=Source::guess_language(file_path);
boost::filesystem::path project_path; if(language && (language->get_id()=="chdr" || language->get_id()=="cpphdr" || language->get_id()=="c" || language->get_id()=="cpp" || language->get_id()=="objc"))
auto &directories=Directories::get(); source_views.emplace_back(new Source::ClangView(file_path, language));
if(directories.cmake && directories.cmake->project_path!="" && file_path.generic_string().substr(0, directories.cmake->project_path.generic_string().size()+1)==directories.cmake->project_path.generic_string()+'/')
project_path=directories.cmake->project_path;
else {
project_path=file_path.parent_path();
CMake cmake(project_path);
if(cmake.project_path!="") {
project_path=cmake.project_path;
Terminal::get().print("Project path for "+file_path.string()+" set to "+project_path.string()+"\n");
}
}
if(language && (language->get_id()=="chdr" || language->get_id()=="cpphdr" || language->get_id()=="c" || language->get_id()=="cpp" || language->get_id()=="objc")) {
CMake::create_default_build(project_path);
source_views.emplace_back(new Source::ClangView(file_path, project_path, language));
}
else else
source_views.emplace_back(new Source::GenericView(file_path, project_path, language)); source_views.emplace_back(new Source::GenericView(file_path, language));
source_views.back()->scroll_to_cursor_delayed=[this](Source::View* view, bool center, bool show_tooltips) { source_views.back()->scroll_to_cursor_delayed=[this](Source::View* view, bool center, bool show_tooltips) {
while(g_main_context_pending(NULL)) while(g_main_context_pending(NULL))
@ -257,31 +243,8 @@ bool Notebook::save(int page) {
view->get_buffer()->set_modified(false); view->get_buffer()->set_modified(false);
//If CMakeLists.txt have been modified: Project::on_save(page);
boost::filesystem::path project_path;
if(view->file_path.filename()=="CMakeLists.txt") {
auto &directories=Directories::get();
if(directories.cmake && directories.cmake->project_path!="" && view->file_path.generic_string().substr(0, directories.cmake->project_path.generic_string().size()+1)==directories.cmake->project_path.generic_string()+'/') {
if(CMake::create_default_build(directories.cmake->project_path, true))
project_path=directories.cmake->project_path;
}
else {
CMake cmake(view->file_path.parent_path());
if(CMake::create_default_build(cmake.project_path, true))
project_path=cmake.project_path;
}
if(project_path!="") {
auto debug_project_path=CMake::get_debug_build_path(project_path);
if(!debug_project_path.empty() && boost::filesystem::exists(debug_project_path))
CMake::create_debug_build(project_path);
for(auto source_view: source_views) {
if(auto source_clang_view=dynamic_cast<Source::ClangView*>(source_view)) {
if(project_path==source_clang_view->project_path)
source_clang_view->full_reparse_needed=true;
}
}
}
}
JDEBUG("end true"); JDEBUG("end true");
return true; return true;
} }
@ -297,19 +260,6 @@ bool Notebook::save_current() {
return save(get_current_page()); return save(get_current_page());
} }
void Notebook::save_project_files() {
if(get_current_page()==-1)
return;
auto current_view=get_current_view();
for(int c=0;c<size();c++) {
auto view=get_view(c);
if(view->get_buffer()->get_modified()) {
if(current_view->project_path==view->project_path)
save(c);
}
}
}
bool Notebook::close(int page) { bool Notebook::close(int page) {
JDEBUG("start"); JDEBUG("start");
if (page!=-1) { if (page!=-1) {
@ -358,14 +308,12 @@ bool Notebook::close_current_page() {
} }
boost::filesystem::path Notebook::get_current_folder() { boost::filesystem::path Notebook::get_current_folder() {
boost::filesystem::path current_path; if(!Directories::get().path.empty())
return Directories::get().path;
if(get_current_page()!=-1) else if(get_current_page()!=-1)
current_path=get_current_view()->project_path; return get_current_view()->file_path.parent_path();
else else
current_path=Directories::get().current_path; return boost::filesystem::path();
return current_path;
} }
bool Notebook::save_modified_dialog(int page) { bool Notebook::save_modified_dialog(int page) {

1
src/notebook.h

@ -34,7 +34,6 @@ public:
void open(const boost::filesystem::path &file_path); void open(const boost::filesystem::path &file_path);
bool save(int page); bool save(int page);
bool save_current(); bool save_current();
void save_project_files();
void configure(int view_nr); void configure(int view_nr);
boost::filesystem::path get_current_folder(); boost::filesystem::path get_current_folder();

157
src/project.cc

@ -2,6 +2,7 @@
#include "config.h" #include "config.h"
#include "terminal.h" #include "terminal.h"
#include "filesystem.h" #include "filesystem.h"
#include "directories.h"
#include <fstream> #include <fstream>
#include "menu.h" #include "menu.h"
#include "notebook.h" #include "notebook.h"
@ -9,15 +10,61 @@
#include "debug_clang.h" #include "debug_clang.h"
#endif #endif
boost::filesystem::path Project::debug_last_stop_file_path;
std::unordered_map<std::string, std::string> Project::run_arguments; std::unordered_map<std::string, std::string> Project::run_arguments;
std::unordered_map<std::string, std::string> Project::debug_run_arguments; std::unordered_map<std::string, std::string> Project::debug_run_arguments;
std::atomic<bool> Project::compiling; std::atomic<bool> Project::compiling(false);
std::atomic<bool> Project::debugging; std::atomic<bool> Project::debugging(false);
std::pair<boost::filesystem::path, std::pair<int, int> > Project::debug_stop; std::pair<boost::filesystem::path, std::pair<int, int> > Project::debug_stop;
boost::filesystem::path Project::debug_last_stop_file_path;
std::unique_ptr<Project::Language> Project::current_language; std::unique_ptr<Project::Language> Project::current_language;
Gtk::Label &Project::debug_status_label() {
static Gtk::Label label;
return label;
}
void Project::save_files(const boost::filesystem::path &path) {
if(Notebook::get().get_current_page()==-1)
return;
for(int c=0;c<Notebook::get().size();c++) {
auto view=Notebook::get().get_view(c);
if(view->get_buffer()->get_modified()) {
if(filesystem::file_in_path(view->file_path, path))
Notebook::get().save(c);
}
}
}
void Project::on_save(int page) {
if(page>=Notebook::get().size())
return;
auto view=Notebook::get().get_view(page);
if(view->language && view->language->get_id()=="cmake") {
boost::filesystem::path cmake_path;
if(view->file_path.filename()=="CMakeLists.txt")
cmake_path=view->file_path;
else
cmake_path=filesystem::find_file_in_path_parents("CMakeLists.txt", view->file_path.parent_path());
if(!cmake_path.empty()) {
auto build=get_build(cmake_path);
if(dynamic_cast<CMake*>(build.get())) {
build->update_default_build(true);
if(boost::filesystem::exists(build->get_debug_build_path()))
build->update_debug_build(true);
for(int c=0;c<Notebook::get().size();c++) {
auto source_view=Notebook::get().get_view(c);
if(auto source_clang_view=dynamic_cast<Source::ClangView*>(source_view)) {
if(filesystem::file_in_path(source_clang_view->file_path, build->project_path))
source_clang_view->full_reparse_needed=true;
}
}
}
}
}
}
void Project::debug_update_status(const std::string &debug_status) { void Project::debug_update_status(const std::string &debug_status) {
if(debug_status.empty()) if(debug_status.empty())
debug_status_label().set_text(""); debug_status_label().set_text("");
@ -59,57 +106,48 @@ void Project::debug_update_stop() {
} }
std::unique_ptr<Project::Language> Project::get_language() { std::unique_ptr<Project::Language> Project::get_language() {
std::unique_ptr<Project::Build> build;
if(Notebook::get().get_current_page()!=-1) { if(Notebook::get().get_current_page()!=-1) {
auto view=Notebook::get().get_current_view(); auto view=Notebook::get().get_current_view();
build=get_build(view->file_path);
if(view->language) { if(view->language) {
auto language_id=view->language->get_id(); auto language_id=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(std::move(build)));
if(language_id=="python") if(language_id=="python")
return std::unique_ptr<Project::Language>(new Project::Python()); return std::unique_ptr<Project::Language>(new Project::Python(std::move(build)));
if(language_id=="js") if(language_id=="js")
return std::unique_ptr<Project::Language>(new Project::JavaScript()); return std::unique_ptr<Project::Language>(new Project::JavaScript(std::move(build)));
if(language_id=="html") if(language_id=="html")
return std::unique_ptr<Project::Language>(new Project::HTML()); return std::unique_ptr<Project::Language>(new Project::HTML(std::move(build)));
} }
} }
else
build=get_build(Directories::get().path);
return std::unique_ptr<Project::Language>(new Project::Clang()); if(dynamic_cast<CMake*>(build.get()))
} return std::unique_ptr<Project::Language>(new Project::Clang(std::move(build)));
std::unique_ptr<CMake> Project::Clang::get_cmake() {
boost::filesystem::path path;
if(Notebook::get().get_current_page()!=-1)
path=Notebook::get().get_current_view()->file_path.parent_path();
else else
path=Directories::get().current_path; return std::unique_ptr<Project::Language>(new Project::Language(std::move(build)));
if(path.empty())
return nullptr;
auto cmake=std::unique_ptr<CMake>(new CMake(path));
if(cmake->project_path.empty())
return nullptr;
if(!CMake::create_default_build(cmake->project_path))
return nullptr;
return cmake;
} }
std::pair<std::string, std::string> Project::Clang::get_run_arguments() { std::pair<std::string, std::string> Project::Clang::get_run_arguments() {
auto cmake=get_cmake(); if(build->get_default_build_path().empty() || !build->update_default_build())
if(!cmake)
return {"", ""}; return {"", ""};
auto project_path=cmake->project_path.string(); auto project_path=build->project_path.string();
auto run_arguments_it=run_arguments.find(project_path); auto run_arguments_it=run_arguments.find(project_path);
std::string arguments; std::string arguments;
if(run_arguments_it!=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().get_current_page()!=-1?Notebook::get().get_current_view()->file_path:"").string(); auto executable=build->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=build->project_path;
auto build_path=CMake::get_default_build_path(project_path); auto build_path=build->get_default_build_path();
if(!build_path.empty()) { if(!build_path.empty()) {
size_t pos=executable.find(project_path.string()); size_t pos=executable.find(project_path.string());
if(pos!=std::string::npos) if(pos!=std::string::npos)
@ -118,36 +156,30 @@ std::pair<std::string, std::string> Project::Clang::get_run_arguments() {
arguments=filesystem::escape_argument(executable); arguments=filesystem::escape_argument(executable);
} }
else else
arguments=filesystem::escape_argument(CMake::get_default_build_path(cmake->project_path)); arguments=filesystem::escape_argument(build->get_default_build_path());
} }
return {project_path, arguments}; return {project_path, arguments};
} }
void Project::Clang::compile() { void Project::Clang::compile() {
auto cmake=get_cmake(); auto default_build_path=build->get_default_build_path();
if(!cmake) if(default_build_path.empty() || !build->update_default_build())
return; return;
auto default_build_path=CMake::get_default_build_path(cmake->project_path);
if(default_build_path.empty())
return;
compiling=true; compiling=true;
Terminal::get().print("Compiling project "+cmake->project_path.string()+"\n"); Terminal::get().print("Compiling project "+build->project_path.string()+"\n");
Terminal::get().async_process(Config::get().project.make_command, default_build_path, [this](int exit_status) { Terminal::get().async_process(Config::get().project.make_command, default_build_path, [this](int exit_status) {
compiling=false; compiling=false;
}); });
} }
void Project::Clang::compile_and_run() { void Project::Clang::compile_and_run() {
auto cmake=get_cmake(); auto default_build_path=build->get_default_build_path();
if(!cmake) if(default_build_path.empty() || !build->update_default_build())
return; return;
auto project_path=cmake->project_path;
auto default_build_path=CMake::get_default_build_path(project_path); auto project_path=build->project_path;
if(default_build_path.empty())
return;
auto run_arguments_it=run_arguments.find(project_path.string()); auto run_arguments_it=run_arguments.find(project_path.string());
std::string arguments; std::string arguments;
@ -155,11 +187,9 @@ void Project::Clang::compile_and_run() {
arguments=run_arguments_it->second; arguments=run_arguments_it->second;
if(arguments.empty()) { if(arguments.empty()) {
arguments=cmake->get_executable(Notebook::get().get_current_page()!=-1?Notebook::get().get_current_view()->file_path:"").string(); arguments=build->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("Warning: could not find executable.\n");
for(auto &path: cmake->paths)
Terminal::get().print(" "+path.string()+"\n");
Terminal::get().print("Solution: either use Project Set Run Arguments, or open a source file within a directory where add_executable is set.\n", true); Terminal::get().print("Solution: either use Project Set Run Arguments, or open a source file within a directory where add_executable is set.\n", true);
return; return;
} }
@ -183,22 +213,21 @@ void Project::Clang::compile_and_run() {
#ifdef JUCI_ENABLE_DEBUG #ifdef JUCI_ENABLE_DEBUG
std::pair<std::string, std::string> Project::Clang::debug_get_run_arguments() { std::pair<std::string, std::string> Project::Clang::debug_get_run_arguments() {
auto cmake=get_cmake(); if(build->get_default_build_path().empty() || !build->update_default_build())
if(!cmake)
return {"", ""}; return {"", ""};
auto project_path=cmake->project_path.string(); auto project_path=build->project_path.string();
auto run_arguments_it=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!=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().get_current_page()!=-1?Notebook::get().get_current_view()->file_path:"").string(); auto executable=build->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=build->project_path;
auto build_path=CMake::get_debug_build_path(project_path); auto build_path=build->get_debug_build_path();
if(!build_path.empty()) { if(!build_path.empty()) {
size_t pos=executable.find(project_path.string()); size_t pos=executable.find(project_path.string());
if(pos!=std::string::npos) if(pos!=std::string::npos)
@ -207,23 +236,17 @@ std::pair<std::string, std::string> Project::Clang::debug_get_run_arguments() {
arguments=filesystem::escape_argument(executable); arguments=filesystem::escape_argument(executable);
} }
else else
arguments=filesystem::escape_argument(CMake::get_debug_build_path(cmake->project_path)); arguments=filesystem::escape_argument(build->get_debug_build_path());
} }
return {project_path, arguments}; return {project_path, arguments};
} }
void Project::Clang::debug_start() { void Project::Clang::debug_start() {
auto cmake=get_cmake(); auto debug_build_path=build->get_debug_build_path();
if(!cmake) if(debug_build_path.empty() || !build->update_debug_build())
return;
auto project_path=cmake->project_path;
auto debug_build_path=CMake::get_debug_build_path(project_path);
if(debug_build_path.empty())
return;
if(!CMake::create_debug_build(project_path))
return; return;
auto project_path=build->project_path;
auto run_arguments_it=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;
@ -231,11 +254,9 @@ void Project::Clang::debug_start() {
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().get_current_page()!=-1?Notebook::get().get_current_view()->file_path:"").string(); run_arguments=build->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("Warning: could not find executable.\n");
for(auto &path: cmake->paths)
Terminal::get().print(" "+path.string()+"\n");
Terminal::get().print("Solution: either use Debug Set Run Arguments, or open a source file within a directory where add_executable is set.\n", true); Terminal::get().print("Solution: either use Debug Set Run Arguments, or open a source file within a directory where add_executable is set.\n", true);
return; return;
} }
@ -248,7 +269,7 @@ 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::get().size();c++) { for(int c=0;c<Notebook::get().size();c++) {
auto view=Notebook::get().get_view(c); auto view=Notebook::get().get_view(c);
if(project_path==view->project_path) { if(filesystem::file_in_path(view->file_path, 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)
breakpoints->emplace_back(view->file_path, iter.get_line()+1); breakpoints->emplace_back(view->file_path, iter.get_line()+1);

55
src/project.h

@ -2,37 +2,36 @@
#define JUCI_PROJECT_H_ #define JUCI_PROJECT_H_
#include <gtkmm.h> #include <gtkmm.h>
#include "cmake.h"
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include "directories.h"
#include <atomic> #include <atomic>
#include <mutex> #include <mutex>
#include <unordered_map>
#include "tooltips.h" #include "tooltips.h"
#include "dispatcher.h" #include "dispatcher.h"
#include <iostream> #include <iostream>
#include "project_build.h"
class Project {
private: namespace Project {
static boost::filesystem::path debug_last_stop_file_path; Gtk::Label &debug_status_label();
public: void save_files(const boost::filesystem::path &path);
static std::unordered_map<std::string, std::string> run_arguments; void on_save(int page);
static std::unordered_map<std::string, std::string> debug_run_arguments;
static std::atomic<bool> compiling; extern boost::filesystem::path debug_last_stop_file_path;
static std::atomic<bool> debugging; extern std::unordered_map<std::string, std::string> run_arguments;
static std::pair<boost::filesystem::path, std::pair<int, int> > debug_stop; extern std::unordered_map<std::string, std::string> debug_run_arguments;
static void debug_update_stop(); extern std::atomic<bool> compiling;
static void debug_update_status(const std::string &debug_status); extern std::atomic<bool> debugging;
extern std::pair<boost::filesystem::path, std::pair<int, int> > debug_stop;
static Gtk::Label &debug_status_label() { void debug_update_stop();
static Gtk::Label label; void debug_update_status(const std::string &debug_status);
return label;
}
class Language { class Language {
public: public:
Language() {} Language(std::unique_ptr<Build> &&build): build(std::move(build)) {}
virtual ~Language() {} virtual ~Language() {}
std::unique_ptr<Build> build;
virtual std::pair<std::string, std::string> get_run_arguments() {return {"", ""};} virtual std::pair<std::string, std::string> get_run_arguments() {return {"", ""};}
virtual void compile() {} virtual void compile() {}
virtual void compile_and_run() {} virtual void compile_and_run() {}
@ -60,11 +59,9 @@ public:
private: private:
Dispatcher dispatcher; Dispatcher dispatcher;
public: public:
Clang() : Language() {} Clang(std::unique_ptr<Build> &&build) : Language(std::move(build)) {}
~Clang() { dispatcher.disconnect(); } ~Clang() { dispatcher.disconnect(); }
std::unique_ptr<CMake> get_cmake();
std::pair<std::string, std::string> get_run_arguments() override; std::pair<std::string, std::string> get_run_arguments() override;
void compile() override; void compile() override;
void compile_and_run() override; void compile_and_run() override;
@ -92,7 +89,7 @@ public:
class Markdown : public Language { class Markdown : public Language {
public: public:
Markdown() : Language() {} Markdown(std::unique_ptr<Build> &&build) : Language(std::move(build)) {}
~Markdown(); ~Markdown();
boost::filesystem::path last_temp_path; boost::filesystem::path last_temp_path;
@ -101,27 +98,27 @@ public:
class Python : public Language { class Python : public Language {
public: public:
Python() : Language() {} Python(std::unique_ptr<Build> &&build) : Language(std::move(build)) {}
void compile_and_run() override; void compile_and_run() override;
}; };
class JavaScript : public Language { class JavaScript : public Language {
public: public:
JavaScript() : Language() {} JavaScript(std::unique_ptr<Build> &&build) : Language(std::move(build)) {}
void compile_and_run() override; void compile_and_run() override;
}; };
class HTML : public Language { class HTML : public Language {
public: public:
HTML() : Language() {} HTML(std::unique_ptr<Build> &&build) : Language(std::move(build)) {}
void compile_and_run() override; void compile_and_run() override;
}; };
static std::unique_ptr<Language> get_language(); std::unique_ptr<Language> get_language();
static std::unique_ptr<Language> current_language; extern std::unique_ptr<Language> current_language;
}; };
#endif // JUCI_PROJECT_H_ #endif // JUCI_PROJECT_H_

77
src/project_build.cc

@ -0,0 +1,77 @@
#include "project_build.h"
#include "config.h"
std::unique_ptr<Project::Build> Project::get_build(const boost::filesystem::path &path) {
auto cmake=new CMake(path);
if(!cmake->project_path.empty())
return std::unique_ptr<Project::Build>(cmake);
else
return std::unique_ptr<Project::Build>(new Project::Build());
}
boost::filesystem::path Project::Build::get_default_build_path() {
boost::filesystem::path default_build_path=Config::get().project.default_build_path;
const std::string path_variable_project_directory_name="<project_directory_name>";
size_t pos=0;
auto default_build_path_string=default_build_path.string();
auto path_filename_string=project_path.filename().string();
while((pos=default_build_path_string.find(path_variable_project_directory_name, pos))!=std::string::npos) {
default_build_path_string.replace(pos, path_variable_project_directory_name.size(), path_filename_string);
pos+=path_filename_string.size();
}
if(pos!=0)
default_build_path=default_build_path_string;
if(default_build_path.is_relative())
default_build_path=project_path/default_build_path;
return default_build_path;
}
boost::filesystem::path Project::Build::get_debug_build_path() {
boost::filesystem::path debug_build_path=Config::get().project.debug_build_path;
const std::string path_variable_project_directory_name="<project_directory_name>";
size_t pos=0;
auto debug_build_path_string=debug_build_path.string();
auto path_filename_string=project_path.filename().string();
while((pos=debug_build_path_string.find(path_variable_project_directory_name, pos))!=std::string::npos) {
debug_build_path_string.replace(pos, path_variable_project_directory_name.size(), path_filename_string);
pos+=path_filename_string.size();
}
if(pos!=0)
debug_build_path=debug_build_path_string;
const std::string path_variable_default_build_path="<default_build_path>";
pos=0;
debug_build_path_string=debug_build_path.string();
auto default_build_path=Config::get().project.default_build_path;
while((pos=debug_build_path_string.find(path_variable_default_build_path, pos))!=std::string::npos) {
debug_build_path_string.replace(pos, path_variable_default_build_path.size(), default_build_path);
pos+=default_build_path.size();
}
if(pos!=0)
debug_build_path=debug_build_path_string;
if(debug_build_path.is_relative())
debug_build_path=project_path/debug_build_path;
return debug_build_path;
}
Project::CMake::CMake(const boost::filesystem::path &path) : Project::Build(), cmake(path) {
project_path=cmake.project_path;
}
bool Project::CMake::update_default_build(bool force) {
return cmake.update_default_build(get_default_build_path(), force);
}
bool Project::CMake::update_debug_build(bool force) {
return cmake.update_debug_build(get_debug_build_path(), force);
}
boost::filesystem::path Project::CMake::get_executable(const boost::filesystem::path &path) {
return cmake.get_executable(path);
}

37
src/project_build.h

@ -0,0 +1,37 @@
#ifndef JUCI_PROJECT_BUILD_H_
#define JUCI_PROJECT_BUILD_H_
#include <boost/filesystem.hpp>
#include "cmake.h"
namespace Project {
class Build {
public:
Build() {}
virtual ~Build() {}
boost::filesystem::path project_path;
boost::filesystem::path get_default_build_path();
virtual bool update_default_build(bool force=false) {return false;}
boost::filesystem::path get_debug_build_path();
virtual bool update_debug_build(bool force=false) {return false;}
virtual boost::filesystem::path get_executable(const boost::filesystem::path &path) {return boost::filesystem::path();}
};
class CMake : public Build {
::CMake cmake;
public:
CMake(const boost::filesystem::path &path);
bool update_default_build(bool force=false) override;
bool update_debug_build(bool force=false) override;
boost::filesystem::path get_executable(const boost::filesystem::path &path) override;
};
std::unique_ptr<Build> get_build(const boost::filesystem::path &path);
}
#endif // JUCI_PROJECT_BUILD_H_

31
src/source.cc

@ -82,7 +82,7 @@ std::string Source::FixIt::string(Glib::RefPtr<Gtk::TextBuffer> buffer) {
////////////// //////////////
AspellConfig* Source::View::spellcheck_config=NULL; AspellConfig* Source::View::spellcheck_config=NULL;
Source::View::View(const boost::filesystem::path &file_path, const boost::filesystem::path &project_path, Glib::RefPtr<Gsv::Language> language): file_path(file_path), project_path(project_path), language(language) { Source::View::View(const boost::filesystem::path &file_path, Glib::RefPtr<Gsv::Language> language): file_path(file_path), language(language) {
get_source_buffer()->begin_not_undoable_action(); get_source_buffer()->begin_not_undoable_action();
if(language) { if(language) {
if(filesystem::read_non_utf8(file_path, get_buffer())==-1) if(filesystem::read_non_utf8(file_path, get_buffer())==-1)
@ -1058,6 +1058,8 @@ bool Source::View::on_key_press_event(GdkEventKey* key) {
return true; return true;
} }
if(last_keyval<GDK_KEY_Shift_L || last_keyval>GDK_KEY_Hyper_R)
previous_non_modifier_keyval=last_keyval;
last_keyval=key->keyval; last_keyval=key->keyval;
if(get_buffer()->get_has_selection()) if(get_buffer()->get_has_selection())
@ -1283,9 +1285,30 @@ bool Source::View::on_key_press_event_basic(GdkEventKey* key) {
return true; return true;
} }
bool stop=Gsv::View::on_key_press_event(key); //Workaround for TextView::on_key_press_event bug sometimes causing segmentation faults
//TODO: figure out the bug and create pull request to gtk
//Have only experienced this on OS X
//Note: valgrind reports issues on TextView::on_key_press_event as well
auto unicode=gdk_keyval_to_unicode(key->keyval);
if((key->state&(GDK_CONTROL_MASK|GDK_META_MASK))==0 && unicode>=32 && unicode!=127 &&
(previous_non_modifier_keyval<GDK_KEY_dead_grave || previous_non_modifier_keyval>GDK_KEY_dead_greek)) {
if(get_buffer()->get_has_selection()) {
Gtk::TextIter selection_start, selection_end;
get_buffer()->get_selection_bounds(selection_start, selection_end);
get_buffer()->erase(selection_start, selection_end);
}
get_buffer()->insert_at_cursor(Glib::ustring(1, unicode));
get_source_buffer()->end_user_action();
//Trick to make the cursor visible right after insertion:
set_cursor_visible(false);
set_cursor_visible();
return true;
}
get_source_buffer()->end_user_action(); get_source_buffer()->end_user_action();
return stop; return Gsv::View::on_key_press_event(key);
} }
//Bracket language indentation //Bracket language indentation
@ -1724,7 +1747,7 @@ std::vector<std::string> Source::View::spellcheck_get_suggestions(const Gtk::Tex
///////////////////// /////////////////////
//// GenericView //// //// GenericView ////
///////////////////// /////////////////////
Source::GenericView::GenericView(const boost::filesystem::path &file_path, const boost::filesystem::path &project_path, Glib::RefPtr<Gsv::Language> language) : View(file_path, project_path, language) { Source::GenericView::GenericView(const boost::filesystem::path &file_path, Glib::RefPtr<Gsv::Language> language) : View(file_path, language) {
configure(); configure();
spellcheck_all=true; spellcheck_all=true;

10
src/source.h

@ -58,7 +58,7 @@ namespace Source {
class View : public Gsv::View { class View : public Gsv::View {
public: public:
View(const boost::filesystem::path &file_path, const boost::filesystem::path &project_path, Glib::RefPtr<Gsv::Language> language); View(const boost::filesystem::path &file_path, Glib::RefPtr<Gsv::Language> language);
~View(); ~View();
virtual void configure(); virtual void configure();
@ -74,7 +74,6 @@ namespace Source {
void paste(); void paste();
boost::filesystem::path file_path; boost::filesystem::path file_path;
boost::filesystem::path project_path;
Glib::RefPtr<Gsv::Language> language; Glib::RefPtr<Gsv::Language> language;
std::function<void()> auto_indent; std::function<void()> auto_indent;
@ -117,8 +116,8 @@ namespace Source {
Tooltips type_tooltips; Tooltips type_tooltips;
virtual void show_diagnostic_tooltips(const Gdk::Rectangle &rectangle) {} virtual void show_diagnostic_tooltips(const Gdk::Rectangle &rectangle) {}
virtual void show_type_tooltips(const Gdk::Rectangle &rectangle) {} virtual void show_type_tooltips(const Gdk::Rectangle &rectangle) {}
gdouble on_motion_last_x; gdouble on_motion_last_x=0.0;
gdouble on_motion_last_y; gdouble on_motion_last_y=0.0;
void set_tooltip_and_dialog_events(); void set_tooltip_and_dialog_events();
std::string get_line(const Gtk::TextIter &iter); std::string get_line(const Gtk::TextIter &iter);
@ -155,6 +154,7 @@ namespace Source {
bool spellcheck_all=false; bool spellcheck_all=false;
std::unique_ptr<SelectionDialog> spellcheck_suggestions_dialog; std::unique_ptr<SelectionDialog> spellcheck_suggestions_dialog;
guint previous_non_modifier_keyval=0;
guint last_keyval=0; guint last_keyval=0;
private: private:
GtkSourceSearchContext *search_context; GtkSourceSearchContext *search_context;
@ -181,7 +181,7 @@ namespace Source {
static Glib::RefPtr<CompletionBuffer> create() {return Glib::RefPtr<CompletionBuffer>(new CompletionBuffer());} static Glib::RefPtr<CompletionBuffer> create() {return Glib::RefPtr<CompletionBuffer>(new CompletionBuffer());}
}; };
public: public:
GenericView(const boost::filesystem::path &file_path, const boost::filesystem::path &project_path, Glib::RefPtr<Gsv::Language> language); GenericView(const boost::filesystem::path &file_path, Glib::RefPtr<Gsv::Language> language);
void parse_language_file(Glib::RefPtr<CompletionBuffer> &completion_buffer, bool &has_context_class, const boost::property_tree::ptree &pt); void parse_language_file(Glib::RefPtr<CompletionBuffer> &completion_buffer, bool &has_context_class, const boost::property_tree::ptree &pt);
}; };

29
src/source_clang.cc

@ -1,7 +1,7 @@
#include "source_clang.h" #include "source_clang.h"
#include "config.h" #include "config.h"
#include "terminal.h" #include "terminal.h"
#include "cmake.h" #include "project_build.h"
#ifdef JUCI_ENABLE_DEBUG #ifdef JUCI_ENABLE_DEBUG
#include "debug_clang.h" #include "debug_clang.h"
#endif #endif
@ -22,8 +22,8 @@ namespace sigc {
clang::Index Source::ClangViewParse::clang_index(0, 0); 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::ClangViewParse::ClangViewParse(const boost::filesystem::path &file_path, Glib::RefPtr<Gsv::Language> language):
Source::View(file_path, project_path, language) { Source::View(file_path, language) {
JDEBUG("start"); JDEBUG("start");
auto tag_table=get_buffer()->get_tag_table(); auto tag_table=get_buffer()->get_tag_table();
@ -174,7 +174,9 @@ void Source::ClangViewParse::soft_reparse() {
} }
std::vector<std::string> Source::ClangViewParse::get_compilation_commands() { std::vector<std::string> Source::ClangViewParse::get_compilation_commands() {
clang::CompilationDatabase db(CMake::get_default_build_path(project_path).string()); auto build=Project::get_build(file_path);
build->update_default_build();
clang::CompilationDatabase db(build->get_default_build_path().string());
clang::CompileCommands commands(file_path.string(), db); clang::CompileCommands commands(file_path.string(), db);
std::vector<clang::CompileCommand> cmds = commands.get_commands(); std::vector<clang::CompileCommand> cmds = commands.get_commands();
std::vector<std::string> arguments; std::vector<std::string> arguments;
@ -450,8 +452,8 @@ void Source::ClangViewParse::show_type_tooltips(const Gdk::Rectangle &rectangle)
////////////////////////////// //////////////////////////////
//// ClangViewAutocomplete /// //// ClangViewAutocomplete ///
////////////////////////////// //////////////////////////////
Source::ClangViewAutocomplete::ClangViewAutocomplete(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path, Glib::RefPtr<Gsv::Language> language): Source::ClangViewAutocomplete::ClangViewAutocomplete(const boost::filesystem::path &file_path, Glib::RefPtr<Gsv::Language> language):
Source::ClangViewParse(file_path, project_path, language), autocomplete_state(AutocompleteState::IDLE) { Source::ClangViewParse(file_path, language), autocomplete_state(AutocompleteState::IDLE) {
get_buffer()->signal_changed().connect([this](){ get_buffer()->signal_changed().connect([this](){
if(autocomplete_dialog && autocomplete_dialog->shown) if(autocomplete_dialog && autocomplete_dialog->shown)
delayed_reparse_connection.disconnect(); delayed_reparse_connection.disconnect();
@ -637,7 +639,7 @@ void Source::ClangViewAutocomplete::autocomplete() {
auto buffer=std::make_shared<Glib::ustring>(get_buffer()->get_text()); auto buffer=std::make_shared<Glib::ustring>(get_buffer()->get_text());
auto iter=get_buffer()->get_insert()->get_iter(); auto iter=get_buffer()->get_insert()->get_iter();
auto line_nr=iter.get_line()+1; auto line_nr=iter.get_line()+1;
auto column_nr=iter.get_line_offset()+1; auto column_nr=iter.get_line_index()+1;
auto pos=iter.get_offset()-1; auto pos=iter.get_offset()-1;
while(pos>=0 && (((*buffer)[pos]>='a' && (*buffer)[pos]<='z') || ((*buffer)[pos]>='A' && (*buffer)[pos]<='Z') || while(pos>=0 && (((*buffer)[pos]>='a' && (*buffer)[pos]<='z') || ((*buffer)[pos]>='A' && (*buffer)[pos]<='Z') ||
((*buffer)[pos]>='0' && (*buffer)[pos]<='9') || (*buffer)[pos]=='_')) { ((*buffer)[pos]>='0' && (*buffer)[pos]<='9') || (*buffer)[pos]=='_')) {
@ -791,8 +793,8 @@ bool Source::ClangViewAutocomplete::full_reparse() {
//////////////////////////// ////////////////////////////
//// ClangViewRefactor ///// //// ClangViewRefactor /////
//////////////////////////// ////////////////////////////
Source::ClangViewRefactor::ClangViewRefactor(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path, Glib::RefPtr<Gsv::Language> language): Source::ClangViewRefactor::ClangViewRefactor(const boost::filesystem::path &file_path, Glib::RefPtr<Gsv::Language> language):
Source::ClangViewAutocomplete(file_path, project_path, language) { Source::ClangViewAutocomplete(file_path, language) {
similar_tokens_tag=get_buffer()->create_tag(); similar_tokens_tag=get_buffer()->create_tag();
similar_tokens_tag->property_weight()=1000; //TODO: replace with Pango::WEIGHT_ULTRAHEAVY in 2016 or so (when Ubuntu 14 is history) similar_tokens_tag->property_weight()=1000; //TODO: replace with Pango::WEIGHT_ULTRAHEAVY in 2016 or so (when Ubuntu 14 is history)
@ -1007,13 +1009,6 @@ Source::ClangViewAutocomplete(file_path, project_path, language) {
auto referenced=cursor.get_referenced(); auto referenced=cursor.get_referenced();
if(referenced) { if(referenced) {
auto usr=referenced.get_usr(); auto usr=referenced.get_usr();
boost::filesystem::path referenced_path=referenced.get_source_location().get_path();
//Terminal::get().print(usr+'\n', true); //TODO: remove
//Return empty if referenced is within project
if(referenced_path.generic_string().substr(0, this->project_path.generic_string().size()+1)==this->project_path.generic_string()+'/')
return data;
data.emplace_back("clang"); data.emplace_back("clang");
@ -1169,7 +1164,7 @@ void Source::ClangViewRefactor::tag_similar_tokens(const Token &token) {
} }
} }
Source::ClangView::ClangView(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path, Glib::RefPtr<Gsv::Language> language): ClangViewRefactor(file_path, project_path, language) { Source::ClangView::ClangView(const boost::filesystem::path &file_path, Glib::RefPtr<Gsv::Language> language): ClangViewRefactor(file_path, language) {
if(language) { if(language) {
get_source_buffer()->set_highlight_syntax(true); get_source_buffer()->set_highlight_syntax(true);
get_source_buffer()->set_language(language); get_source_buffer()->set_language(language);

8
src/source_clang.h

@ -24,7 +24,7 @@ namespace Source {
int kind; int kind;
}; };
ClangViewParse(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path, Glib::RefPtr<Gsv::Language> language); ClangViewParse(const boost::filesystem::path &file_path, Glib::RefPtr<Gsv::Language> language);
void configure() override; void configure() override;
@ -71,7 +71,7 @@ namespace Source {
std::string brief_comments; std::string brief_comments;
}; };
ClangViewAutocomplete(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path, Glib::RefPtr<Gsv::Language> language); ClangViewAutocomplete(const boost::filesystem::path &file_path, Glib::RefPtr<Gsv::Language> language);
virtual void async_delete(); virtual void async_delete();
bool full_reparse() override; bool full_reparse() override;
@ -96,7 +96,7 @@ namespace Source {
class ClangViewRefactor : public ClangViewAutocomplete { class ClangViewRefactor : public ClangViewAutocomplete {
public: public:
ClangViewRefactor(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path, Glib::RefPtr<Gsv::Language> language); ClangViewRefactor(const boost::filesystem::path &file_path, Glib::RefPtr<Gsv::Language> language);
protected: protected:
sigc::connection delayed_tag_similar_tokens_connection; sigc::connection delayed_tag_similar_tokens_connection;
private: private:
@ -109,7 +109,7 @@ namespace Source {
class ClangView : public ClangViewRefactor { class ClangView : public ClangViewRefactor {
public: public:
ClangView(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path, Glib::RefPtr<Gsv::Language> language); ClangView(const boost::filesystem::path &file_path, Glib::RefPtr<Gsv::Language> language);
void async_delete() override; void async_delete() override;
}; };
} }

194
src/window.cc

@ -6,6 +6,8 @@
//#include "api.h" //#include "api.h"
#include "dialogs.h" #include "dialogs.h"
#include "filesystem.h" #include "filesystem.h"
#include "project.h"
#include "entrybox.h"
namespace sigc { namespace sigc {
#ifndef SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE #ifndef SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE
@ -38,7 +40,7 @@ Window::Window() : notebook(Notebook::get()) {
directories_scrolled_window.add(Directories::get()); directories_scrolled_window.add(Directories::get());
directory_and_notebook_panes.pack1(directories_scrolled_window, Gtk::SHRINK); directory_and_notebook_panes.pack1(directories_scrolled_window, Gtk::SHRINK);
notebook_vbox.pack_start(notebook); notebook_vbox.pack_start(notebook);
notebook_vbox.pack_end(entry_box, Gtk::PACK_SHRINK); notebook_vbox.pack_end(EntryBox::get(), Gtk::PACK_SHRINK);
directory_and_notebook_panes.pack2(notebook_vbox, Gtk::SHRINK); directory_and_notebook_panes.pack2(notebook_vbox, Gtk::SHRINK);
directory_and_notebook_panes.set_position(static_cast<int>(0.2*Config::get().window.default_size.first)); directory_and_notebook_panes.set_position(static_cast<int>(0.2*Config::get().window.default_size.first));
vpaned.set_position(static_cast<int>(0.75*Config::get().window.default_size.second)); vpaned.set_position(static_cast<int>(0.75*Config::get().window.default_size.second));
@ -72,17 +74,17 @@ Window::Window() : notebook(Notebook::get()) {
Terminal::get().queue_draw(); Terminal::get().queue_draw();
}); });
entry_box.signal_show().connect([this](){ EntryBox::get().signal_show().connect([this](){
vpaned.set_focus_chain({&directory_and_notebook_panes}); vpaned.set_focus_chain({&directory_and_notebook_panes});
directory_and_notebook_panes.set_focus_chain({&notebook_vbox}); directory_and_notebook_panes.set_focus_chain({&notebook_vbox});
notebook_vbox.set_focus_chain({&entry_box}); notebook_vbox.set_focus_chain({&EntryBox::get()});
}); });
entry_box.signal_hide().connect([this](){ EntryBox::get().signal_hide().connect([this](){
vpaned.unset_focus_chain(); vpaned.unset_focus_chain();
directory_and_notebook_panes.unset_focus_chain(); directory_and_notebook_panes.unset_focus_chain();
notebook_vbox.unset_focus_chain(); notebook_vbox.unset_focus_chain();
}); });
entry_box.signal_hide().connect([this]() { EntryBox::get().signal_hide().connect([this]() {
if(notebook.get_current_page()!=-1) { if(notebook.get_current_page()!=-1) {
notebook.get_current_view()->grab_focus(); notebook.get_current_view()->grab_focus();
} }
@ -91,9 +93,9 @@ Window::Window() : notebook(Notebook::get()) {
notebook.signal_switch_page().connect([this](Gtk::Widget* page, guint page_num) { notebook.signal_switch_page().connect([this](Gtk::Widget* page, guint page_num) {
if(notebook.get_current_page()!=-1) { if(notebook.get_current_page()!=-1) {
auto view=notebook.get_current_view(); auto view=notebook.get_current_view();
if(search_entry_shown && entry_box.labels.size()>0) { if(search_entry_shown && EntryBox::get().labels.size()>0) {
view->update_search_occurrences=[this](int number){ view->update_search_occurrences=[this](int number){
entry_box.labels.begin()->update(0, std::to_string(number)); EntryBox::get().labels.begin()->update(0, std::to_string(number));
}; };
view->search_highlight(last_search, case_sensitive_search, regex_search); view->search_highlight(last_search, case_sensitive_search, regex_search);
} }
@ -114,7 +116,7 @@ Window::Window() : notebook(Notebook::get()) {
} }
}); });
notebook.signal_page_removed().connect([this](Gtk::Widget* page, guint page_num) { notebook.signal_page_removed().connect([this](Gtk::Widget* page, guint page_num) {
entry_box.hide(); EntryBox::get().hide();
}); });
about.signal_response().connect([this](int d){ about.signal_response().connect([this](int d){
@ -161,14 +163,14 @@ void Window::set_menu_actions() {
}); });
menu.add_action("new_file", [this]() { menu.add_action("new_file", [this]() {
boost::filesystem::path path = Dialog::new_file(); boost::filesystem::path path = Dialog::new_file(notebook.get_current_folder());
if(path!="") { if(path!="") {
if(boost::filesystem::exists(path)) { if(boost::filesystem::exists(path)) {
Terminal::get().print("Error: "+path.string()+" already exists.\n", true); Terminal::get().print("Error: "+path.string()+" already exists.\n", true);
} }
else { else {
if(filesystem::write(path)) { if(filesystem::write(path)) {
if(Directories::get().current_path!="") if(Directories::get().path!="")
Directories::get().update(); Directories::get().update();
notebook.open(path); notebook.open(path);
Terminal::get().print("New file "+path.string()+" created.\n"); Terminal::get().print("New file "+path.string()+" created.\n");
@ -180,12 +182,12 @@ void Window::set_menu_actions() {
}); });
menu.add_action("new_folder", [this]() { menu.add_action("new_folder", [this]() {
auto time_now=std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); auto time_now=std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
boost::filesystem::path path = Dialog::new_folder(); boost::filesystem::path path = Dialog::new_folder(notebook.get_current_folder());
if(path!="" && boost::filesystem::exists(path)) { if(path!="" && boost::filesystem::exists(path)) {
boost::system::error_code ec; boost::system::error_code ec;
auto last_write_time=boost::filesystem::last_write_time(path, ec); auto last_write_time=boost::filesystem::last_write_time(path, ec);
if(!ec && last_write_time>=time_now) { if(!ec && last_write_time>=time_now) {
if(Directories::get().current_path!="") if(Directories::get().path!="")
Directories::get().update(); Directories::get().update();
Terminal::get().print("New folder "+path.string()+" created.\n"); Terminal::get().print("New folder "+path.string()+" created.\n");
} }
@ -195,7 +197,7 @@ void Window::set_menu_actions() {
} }
}); });
menu.add_action("new_project_cpp", [this]() { menu.add_action("new_project_cpp", [this]() {
boost::filesystem::path project_path = Dialog::new_folder(); boost::filesystem::path project_path = Dialog::new_folder(notebook.get_current_folder());
if(project_path!="") { if(project_path!="") {
auto project_name=project_path.filename().string(); auto project_name=project_path.filename().string();
for(size_t c=0;c<project_name.size();c++) { for(size_t c=0;c<project_name.size();c++) {
@ -227,12 +229,12 @@ void Window::set_menu_actions() {
}); });
menu.add_action("open_file", [this]() { menu.add_action("open_file", [this]() {
auto path=Dialog::open_file(); auto path=Dialog::open_file(notebook.get_current_folder());
if(path!="") if(path!="")
notebook.open(path); notebook.open(path);
}); });
menu.add_action("open_folder", [this]() { menu.add_action("open_folder", [this]() {
auto path = Dialog::open_folder(); auto path = Dialog::open_folder(notebook.get_current_folder());
if (path!="" && boost::filesystem::exists(path)) if (path!="" && boost::filesystem::exists(path))
Directories::get().open(path); Directories::get().open(path);
}); });
@ -260,7 +262,7 @@ void Window::set_menu_actions() {
if(file) { if(file) {
file << notebook.get_current_view()->get_buffer()->get_text(); file << notebook.get_current_view()->get_buffer()->get_text();
file.close(); file.close();
if(Directories::get().current_path!="") if(Directories::get().path!="")
Directories::get().update(); Directories::get().update();
notebook.open(path); notebook.open(path);
Terminal::get().print("File saved to: " + notebook.get_current_view()->file_path.string()+"\n"); Terminal::get().print("File saved to: " + notebook.get_current_view()->file_path.string()+"\n");
@ -504,54 +506,56 @@ void Window::set_menu_actions() {
if(run_arguments->second.empty()) if(run_arguments->second.empty())
return; return;
entry_box.clear(); EntryBox::get().clear();
entry_box.labels.emplace_back(); EntryBox::get().labels.emplace_back();
auto label_it=entry_box.labels.begin(); auto label_it=EntryBox::get().labels.begin();
label_it->update=[label_it](int state, const std::string& message){ label_it->update=[label_it](int state, const std::string& message){
label_it->set_text("Set empty to let juCi++ deduce executable"); label_it->set_text("Set empty to let juCi++ deduce executable");
}; };
label_it->update(0, ""); label_it->update(0, "");
entry_box.entries.emplace_back(run_arguments->second, [this, run_arguments](const std::string& content){ EntryBox::get().entries.emplace_back(run_arguments->second, [this, run_arguments](const std::string& content){
Project::run_arguments[run_arguments->first]=content; Project::run_arguments[run_arguments->first]=content;
entry_box.hide(); EntryBox::get().hide();
}, 50); }, 50);
auto entry_it=entry_box.entries.begin(); auto entry_it=EntryBox::get().entries.begin();
entry_it->set_placeholder_text("Project: Set Run Arguments"); entry_it->set_placeholder_text("Project: Set Run Arguments");
entry_box.buttons.emplace_back("Project: set run arguments", [this, entry_it](){ EntryBox::get().buttons.emplace_back("Project: set run arguments", [this, entry_it](){
entry_it->activate(); entry_it->activate();
}); });
entry_box.show(); EntryBox::get().show();
}); });
menu.add_action("compile_and_run", [this]() { menu.add_action("compile_and_run", [this]() {
if(Project::compiling || Project::debugging) if(Project::compiling || Project::debugging)
return; return;
Project::current_language=Project::get_language();
if(Config::get().project.save_on_compile_or_run) if(Config::get().project.save_on_compile_or_run)
notebook.save_project_files(); Project::save_files(Project::current_language->build->project_path);
Project::current_language=Project::get_language();
Project::current_language->compile_and_run(); Project::current_language->compile_and_run();
}); });
menu.add_action("compile", [this]() { menu.add_action("compile", [this]() {
if(Project::compiling || Project::debugging) if(Project::compiling || Project::debugging)
return; return;
Project::current_language=Project::get_language();
if(Config::get().project.save_on_compile_or_run) if(Config::get().project.save_on_compile_or_run)
notebook.save_project_files(); Project::save_files(Project::current_language->build->project_path);
Project::current_language=Project::get_language();
Project::current_language->compile(); Project::current_language->compile();
}); });
menu.add_action("run_command", [this]() { menu.add_action("run_command", [this]() {
entry_box.clear(); EntryBox::get().clear();
entry_box.labels.emplace_back(); EntryBox::get().labels.emplace_back();
auto label_it=entry_box.labels.begin(); auto label_it=EntryBox::get().labels.begin();
label_it->update=[label_it](int state, const std::string& message){ label_it->update=[label_it](int state, const std::string& message){
label_it->set_text("Run Command directory order: file project path, opened directory, current directory"); label_it->set_text("Run Command directory order: opened directory, file path, current directory");
}; };
label_it->update(0, ""); label_it->update(0, "");
entry_box.entries.emplace_back(last_run_command, [this](const std::string& content){ EntryBox::get().entries.emplace_back(last_run_command, [this](const std::string& content){
if(content!="") { if(content!="") {
last_run_command=content; last_run_command=content;
auto run_path=notebook.get_current_folder(); auto run_path=notebook.get_current_folder();
@ -561,14 +565,14 @@ void Window::set_menu_actions() {
Terminal::get().async_print(content+" returned: "+std::to_string(exit_status)+'\n'); Terminal::get().async_print(content+" returned: "+std::to_string(exit_status)+'\n');
}); });
} }
entry_box.hide(); EntryBox::get().hide();
}, 30); }, 30);
auto entry_it=entry_box.entries.begin(); auto entry_it=EntryBox::get().entries.begin();
entry_it->set_placeholder_text("Command"); entry_it->set_placeholder_text("Command");
entry_box.buttons.emplace_back("Run command", [this, entry_it](){ EntryBox::get().buttons.emplace_back("Run command", [this, entry_it](){
entry_it->activate(); entry_it->activate();
}); });
entry_box.show(); EntryBox::get().show();
}); });
menu.add_action("kill_last_running", [this]() { menu.add_action("kill_last_running", [this]() {
@ -585,23 +589,23 @@ void Window::set_menu_actions() {
if(run_arguments->second.empty()) if(run_arguments->second.empty())
return; return;
entry_box.clear(); EntryBox::get().clear();
entry_box.labels.emplace_back(); EntryBox::get().labels.emplace_back();
auto label_it=entry_box.labels.begin(); auto label_it=EntryBox::get().labels.begin();
label_it->update=[label_it](int state, const std::string& message){ label_it->update=[label_it](int state, const std::string& message){
label_it->set_text("Set empty to let juCi++ deduce executable"); label_it->set_text("Set empty to let juCi++ deduce executable");
}; };
label_it->update(0, ""); label_it->update(0, "");
entry_box.entries.emplace_back(run_arguments->second, [this, run_arguments](const std::string& content){ EntryBox::get().entries.emplace_back(run_arguments->second, [this, run_arguments](const std::string& content){
Project::debug_run_arguments[run_arguments->first]=content; Project::debug_run_arguments[run_arguments->first]=content;
entry_box.hide(); EntryBox::get().hide();
}, 50); }, 50);
auto entry_it=entry_box.entries.begin(); auto entry_it=EntryBox::get().entries.begin();
entry_it->set_placeholder_text("Debug: Set Run Arguments"); entry_it->set_placeholder_text("Debug: Set Run Arguments");
entry_box.buttons.emplace_back("Debug: set run arguments", [this, entry_it](){ EntryBox::get().buttons.emplace_back("Debug: set run arguments", [this, entry_it](){
entry_it->activate(); entry_it->activate();
}); });
entry_box.show(); EntryBox::get().show();
}); });
menu.add_action("debug_start_continue", [this](){ menu.add_action("debug_start_continue", [this](){
if(Project::compiling) if(Project::compiling)
@ -611,11 +615,11 @@ void Window::set_menu_actions() {
return; return;
} }
if(Config::get().project.save_on_compile_or_run)
notebook.save_project_files();
Project::current_language=Project::get_language(); Project::current_language=Project::get_language();
if(Config::get().project.save_on_compile_or_run)
Project::save_files(Project::current_language->build->project_path);
Project::current_language->debug_start(); Project::current_language->debug_start();
}); });
menu.add_action("debug_stop", [this]() { menu.add_action("debug_stop", [this]() {
@ -647,21 +651,21 @@ void Window::set_menu_actions() {
Project::current_language->debug_show_variables(); Project::current_language->debug_show_variables();
}); });
menu.add_action("debug_run_command", [this]() { menu.add_action("debug_run_command", [this]() {
entry_box.clear(); EntryBox::get().clear();
entry_box.entries.emplace_back(last_run_debug_command, [this](const std::string& content){ EntryBox::get().entries.emplace_back(last_run_debug_command, [this](const std::string& content){
if(content!="") { if(content!="") {
if(Project::current_language) if(Project::current_language)
Project::current_language->debug_run_command(content); Project::current_language->debug_run_command(content);
last_run_debug_command=content; last_run_debug_command=content;
} }
entry_box.hide(); EntryBox::get().hide();
}, 30); }, 30);
auto entry_it=entry_box.entries.begin(); auto entry_it=EntryBox::get().entries.begin();
entry_it->set_placeholder_text("Debug Command"); entry_it->set_placeholder_text("Debug Command");
entry_box.buttons.emplace_back("Run debug command", [this, entry_it](){ EntryBox::get().buttons.emplace_back("Run debug command", [this, entry_it](){
entry_it->activate(); entry_it->activate();
}); });
entry_box.show(); EntryBox::get().show();
}); });
menu.add_action("debug_toggle_breakpoint", [this](){ menu.add_action("debug_toggle_breakpoint", [this](){
if(notebook.get_current_page()!=-1) { if(notebook.get_current_page()!=-1) {
@ -766,7 +770,7 @@ void Window::activate_menu_items(bool activate) {
bool Window::on_key_press_event(GdkEventKey *event) { bool Window::on_key_press_event(GdkEventKey *event) {
if(event->keyval==GDK_KEY_Escape) { if(event->keyval==GDK_KEY_Escape) {
entry_box.hide(); EntryBox::get().hide();
} }
#ifdef __APPLE__ //For Apple's Command-left, right, up, down keys #ifdef __APPLE__ //For Apple's Command-left, right, up, down keys
else if((event->state & GDK_META_MASK)>0 && (event->state & GDK_MOD1_MASK)==0) { else if((event->state & GDK_META_MASK)>0 && (event->state & GDK_MOD1_MASK)==0) {
@ -813,9 +817,9 @@ bool Window::on_delete_event(GdkEventAny *event) {
} }
void Window::search_and_replace_entry() { void Window::search_and_replace_entry() {
entry_box.clear(); EntryBox::get().clear();
entry_box.labels.emplace_back(); EntryBox::get().labels.emplace_back();
auto label_it=entry_box.labels.begin(); auto label_it=EntryBox::get().labels.begin();
label_it->update=[label_it](int state, const std::string& message){ label_it->update=[label_it](int state, const std::string& message){
if(state==0) { if(state==0) {
try { try {
@ -830,11 +834,11 @@ void Window::search_and_replace_entry() {
catch(const std::exception &e) {} catch(const std::exception &e) {}
} }
}; };
entry_box.entries.emplace_back(last_search, [this](const std::string& content){ EntryBox::get().entries.emplace_back(last_search, [this](const std::string& content){
if(notebook.get_current_page()!=-1) if(notebook.get_current_page()!=-1)
notebook.get_current_view()->search_forward(); notebook.get_current_view()->search_forward();
}); });
auto search_entry_it=entry_box.entries.begin(); auto search_entry_it=EntryBox::get().entries.begin();
search_entry_it->set_placeholder_text("Find"); search_entry_it->set_placeholder_text("Find");
if(notebook.get_current_page()!=-1) { if(notebook.get_current_page()!=-1) {
notebook.get_current_view()->update_search_occurrences=[label_it](int number){ notebook.get_current_view()->update_search_occurrences=[label_it](int number){
@ -855,11 +859,11 @@ void Window::search_and_replace_entry() {
notebook.get_current_view()->search_highlight(search_entry_it->get_text(), case_sensitive_search, regex_search); notebook.get_current_view()->search_highlight(search_entry_it->get_text(), case_sensitive_search, regex_search);
}); });
entry_box.entries.emplace_back(last_replace, [this](const std::string &content){ EntryBox::get().entries.emplace_back(last_replace, [this](const std::string &content){
if(notebook.get_current_page()!=-1) if(notebook.get_current_page()!=-1)
notebook.get_current_view()->replace_forward(content); notebook.get_current_view()->replace_forward(content);
}); });
auto replace_entry_it=entry_box.entries.begin(); auto replace_entry_it=EntryBox::get().entries.begin();
replace_entry_it++; replace_entry_it++;
replace_entry_it->set_placeholder_text("Replace"); replace_entry_it->set_placeholder_text("Replace");
replace_entry_it->signal_key_press_event().connect([this, replace_entry_it](GdkEventKey* event){ replace_entry_it->signal_key_press_event().connect([this, replace_entry_it](GdkEventKey* event){
@ -873,25 +877,25 @@ void Window::search_and_replace_entry() {
last_replace=replace_entry_it->get_text(); last_replace=replace_entry_it->get_text();
}); });
entry_box.buttons.emplace_back("Replace all", [this, replace_entry_it](){ EntryBox::get().buttons.emplace_back("Replace all", [this, replace_entry_it](){
if(notebook.get_current_page()!=-1) if(notebook.get_current_page()!=-1)
notebook.get_current_view()->replace_all(replace_entry_it->get_text()); notebook.get_current_view()->replace_all(replace_entry_it->get_text());
}); });
entry_box.toggle_buttons.emplace_back("Match case"); EntryBox::get().toggle_buttons.emplace_back("Match case");
entry_box.toggle_buttons.back().set_active(case_sensitive_search); EntryBox::get().toggle_buttons.back().set_active(case_sensitive_search);
entry_box.toggle_buttons.back().on_activate=[this, search_entry_it](){ EntryBox::get().toggle_buttons.back().on_activate=[this, search_entry_it](){
case_sensitive_search=!case_sensitive_search; case_sensitive_search=!case_sensitive_search;
if(notebook.get_current_page()!=-1) if(notebook.get_current_page()!=-1)
notebook.get_current_view()->search_highlight(search_entry_it->get_text(), case_sensitive_search, regex_search); notebook.get_current_view()->search_highlight(search_entry_it->get_text(), case_sensitive_search, regex_search);
}; };
entry_box.toggle_buttons.emplace_back("Use regex"); EntryBox::get().toggle_buttons.emplace_back("Use regex");
entry_box.toggle_buttons.back().set_active(regex_search); EntryBox::get().toggle_buttons.back().set_active(regex_search);
entry_box.toggle_buttons.back().on_activate=[this, search_entry_it](){ EntryBox::get().toggle_buttons.back().on_activate=[this, search_entry_it](){
regex_search=!regex_search; regex_search=!regex_search;
if(notebook.get_current_page()!=-1) if(notebook.get_current_page()!=-1)
notebook.get_current_view()->search_highlight(search_entry_it->get_text(), case_sensitive_search, regex_search); notebook.get_current_view()->search_highlight(search_entry_it->get_text(), case_sensitive_search, regex_search);
}; };
entry_box.signal_hide().connect([this]() { EntryBox::get().signal_hide().connect([this]() {
for(int c=0;c<notebook.size();c++) { for(int c=0;c<notebook.size();c++) {
notebook.get_view(c)->update_search_occurrences=nullptr; notebook.get_view(c)->update_search_occurrences=nullptr;
notebook.get_view(c)->search_highlight("", case_sensitive_search, regex_search); notebook.get_view(c)->search_highlight("", case_sensitive_search, regex_search);
@ -899,19 +903,19 @@ void Window::search_and_replace_entry() {
search_entry_shown=false; search_entry_shown=false;
}); });
search_entry_shown=true; search_entry_shown=true;
entry_box.show(); EntryBox::get().show();
} }
void Window::set_tab_entry() { void Window::set_tab_entry() {
entry_box.clear(); EntryBox::get().clear();
if(notebook.get_current_page()!=-1) { if(notebook.get_current_page()!=-1) {
auto tab_char_and_size=notebook.get_current_view()->get_tab_char_and_size(); auto tab_char_and_size=notebook.get_current_view()->get_tab_char_and_size();
entry_box.labels.emplace_back(); EntryBox::get().labels.emplace_back();
auto label_it=entry_box.labels.begin(); auto label_it=EntryBox::get().labels.begin();
entry_box.entries.emplace_back(std::to_string(tab_char_and_size.second)); EntryBox::get().entries.emplace_back(std::to_string(tab_char_and_size.second));
auto entry_tab_size_it=entry_box.entries.begin(); auto entry_tab_size_it=EntryBox::get().entries.begin();
entry_tab_size_it->set_placeholder_text("Tab size"); entry_tab_size_it->set_placeholder_text("Tab size");
char tab_char=tab_char_and_size.first; char tab_char=tab_char_and_size.first;
@ -921,8 +925,8 @@ void Window::set_tab_entry() {
else if(tab_char=='\t') else if(tab_char=='\t')
tab_char_string="tab"; tab_char_string="tab";
entry_box.entries.emplace_back(tab_char_string); EntryBox::get().entries.emplace_back(tab_char_string);
auto entry_tab_char_it=entry_box.entries.rbegin(); auto entry_tab_char_it=EntryBox::get().entries.rbegin();
entry_tab_char_it->set_placeholder_text("Tab char"); entry_tab_char_it->set_placeholder_text("Tab char");
const auto activate_function=[this, entry_tab_char_it, entry_tab_size_it, label_it](const std::string& content){ const auto activate_function=[this, entry_tab_char_it, entry_tab_size_it, label_it](const std::string& content){
@ -942,7 +946,7 @@ void Window::set_tab_entry() {
if(tab_char!=0 && tab_size>0) { if(tab_char!=0 && tab_size>0) {
notebook.get_current_view()->set_tab_char_and_size(tab_char, tab_size); notebook.get_current_view()->set_tab_char_and_size(tab_char, tab_size);
entry_box.hide(); EntryBox::get().hide();
} }
else { else {
label_it->set_text("Tab size must be >0 and tab char set to either 'space' or 'tab'"); label_it->set_text("Tab size must be >0 and tab char set to either 'space' or 'tab'");
@ -953,18 +957,18 @@ void Window::set_tab_entry() {
entry_tab_char_it->on_activate=activate_function; entry_tab_char_it->on_activate=activate_function;
entry_tab_size_it->on_activate=activate_function; entry_tab_size_it->on_activate=activate_function;
entry_box.buttons.emplace_back("Set tab in current buffer", [this, entry_tab_char_it](){ EntryBox::get().buttons.emplace_back("Set tab in current buffer", [this, entry_tab_char_it](){
entry_tab_char_it->activate(); entry_tab_char_it->activate();
}); });
entry_box.show(); EntryBox::get().show();
} }
} }
void Window::goto_line_entry() { void Window::goto_line_entry() {
entry_box.clear(); EntryBox::get().clear();
if(notebook.get_current_page()!=-1) { if(notebook.get_current_page()!=-1) {
entry_box.entries.emplace_back("", [this](const std::string& content){ EntryBox::get().entries.emplace_back("", [this](const std::string& content){
if(notebook.get_current_page()!=-1) { if(notebook.get_current_page()!=-1) {
auto view=notebook.get_current_view(); auto view=notebook.get_current_view();
try { try {
@ -977,31 +981,31 @@ void Window::goto_line_entry() {
} }
} }
catch(const std::exception &e) {} catch(const std::exception &e) {}
entry_box.hide(); EntryBox::get().hide();
} }
}); });
auto entry_it=entry_box.entries.begin(); auto entry_it=EntryBox::get().entries.begin();
entry_it->set_placeholder_text("Line number"); entry_it->set_placeholder_text("Line number");
entry_box.buttons.emplace_back("Go to line", [this, entry_it](){ EntryBox::get().buttons.emplace_back("Go to line", [this, entry_it](){
entry_it->activate(); entry_it->activate();
}); });
entry_box.show(); EntryBox::get().show();
} }
} }
void Window::rename_token_entry() { void Window::rename_token_entry() {
entry_box.clear(); EntryBox::get().clear();
if(notebook.get_current_page()!=-1) { if(notebook.get_current_page()!=-1) {
if(notebook.get_current_view()->get_token) { if(notebook.get_current_view()->get_token) {
auto token=std::make_shared<Source::Token>(notebook.get_current_view()->get_token()); auto token=std::make_shared<Source::Token>(notebook.get_current_view()->get_token());
if(*token) { if(*token) {
entry_box.labels.emplace_back(); EntryBox::get().labels.emplace_back();
auto label_it=entry_box.labels.begin(); auto label_it=EntryBox::get().labels.begin();
label_it->update=[label_it](int state, const std::string& message){ label_it->update=[label_it](int state, const std::string& message){
label_it->set_text("Warning: only opened and parsed tabs will have its content renamed, and modified files will be saved"); label_it->set_text("Warning: only opened and parsed tabs will have its content renamed, and modified files will be saved");
}; };
label_it->update(0, ""); label_it->update(0, "");
entry_box.entries.emplace_back(token->spelling, [this, token](const std::string& content){ EntryBox::get().entries.emplace_back(token->spelling, [this, token](const std::string& content){
if(notebook.get_current_page()!=-1 && content!=token->spelling) { if(notebook.get_current_page()!=-1 && content!=token->spelling) {
std::vector<int> modified_pages; std::vector<int> modified_pages;
for(int c=0;c<notebook.size();c++) { for(int c=0;c<notebook.size();c++) {
@ -1017,15 +1021,15 @@ void Window::rename_token_entry() {
} }
for(auto &page: modified_pages) for(auto &page: modified_pages)
notebook.get_view(page)->soft_reparse_needed=false; notebook.get_view(page)->soft_reparse_needed=false;
entry_box.hide(); EntryBox::get().hide();
} }
}); });
auto entry_it=entry_box.entries.begin(); auto entry_it=EntryBox::get().entries.begin();
entry_it->set_placeholder_text("New name"); entry_it->set_placeholder_text("New name");
entry_box.buttons.emplace_back("Rename", [this, entry_it](){ EntryBox::get().buttons.emplace_back("Rename", [this, entry_it](){
entry_it->activate(); entry_it->activate();
}); });
entry_box.show(); EntryBox::get().show();
} }
} }
} }

3
src/window.h

@ -2,9 +2,7 @@
#define JUCI_WINDOW_H_ #define JUCI_WINDOW_H_
#include <gtkmm.h> #include <gtkmm.h>
#include "entrybox.h"
#include "notebook.h" #include "notebook.h"
#include "project.h"
#include <atomic> #include <atomic>
class Window : public Gtk::ApplicationWindow { class Window : public Gtk::ApplicationWindow {
@ -30,7 +28,6 @@ private:
Gtk::ScrolledWindow terminal_scrolled_window; Gtk::ScrolledWindow terminal_scrolled_window;
Gtk::HBox info_and_status_hbox; Gtk::HBox info_and_status_hbox;
Gtk::AboutDialog about; Gtk::AboutDialog about;
EntryBox entry_box;
void configure(); void configure();
void set_menu_actions(); void set_menu_actions();

Loading…
Cancel
Save