Browse Source

Merge branch 'master' of http://github.com/eidheim/jucipp

merge-requests/365/head
Jørgen Lien Sellæg 10 years ago
parent
commit
2b404be313
  1. 7
      src/config.cc
  2. 236
      src/directories.cc
  3. 24
      src/directories.h
  4. 16
      src/files.h
  5. 2
      src/juci.cc
  6. 1
      src/notebook.cc
  7. 164
      src/source.cc
  8. 17
      src/source.h
  9. 153
      src/window.cc
  10. 4
      src/window.h

7
src/config.cc

@ -45,10 +45,9 @@ void MainConfig::GenerateSource() {
auto source_cfg = Singleton::Config::source(); auto source_cfg = Singleton::Config::source();
auto source_json = cfg.get_child("source"); auto source_json = cfg.get_child("source");
source_cfg->tab_size = source_json.get<unsigned>("tab_size"); source_cfg->default_tab_char = source_json.get<char>("default_tab_char");
source_cfg->tab_char = source_json.get<char>("tab_char"); source_cfg->default_tab_size = source_json.get<unsigned>("default_tab_size");
for(unsigned c=0;c<source_cfg->tab_size;c++) source_cfg->auto_tab_char_and_size = source_json.get<bool>("auto_tab_char_and_size");
source_cfg->tab+=source_cfg->tab_char;
source_cfg->highlight_current_line = source_json.get_value<bool>("highlight_current_line"); source_cfg->highlight_current_line = source_json.get_value<bool>("highlight_current_line");
source_cfg->show_line_numbers = source_json.get_value<bool>("show_line_numbers"); source_cfg->show_line_numbers = source_json.get_value<bool>("show_line_numbers");

236
src/directories.cc

@ -3,7 +3,7 @@
#include "logging.h" #include "logging.h"
#include "singletons.h" #include "singletons.h"
#include <algorithm> #include <algorithm>
#include "boost/algorithm/string.hpp" #include <unordered_set>
#include <iostream> //TODO: remove #include <iostream> //TODO: remove
using namespace std; //TODO: remove using namespace std; //TODO: remove
@ -12,78 +12,169 @@ namespace sigc {
SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE
} }
Directories::Directories() { Directories::Directories() : stop_update_thread(false) {
DEBUG("adding treeview to scrolledwindow"); DEBUG("adding treeview to scrolledwindow");
add(tree_view); add(tree_view);
set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
tree_store = Gtk::TreeStore::create(column_record); tree_store = Gtk::TreeStore::create(column_record);
tree_view.set_model(tree_store); tree_view.set_model(tree_store);
tree_view.append_column("", column_record.name); tree_view.append_column("", column_record.name);
tree_store->set_sort_column(0, Gtk::SortType::SORT_ASCENDING); tree_store->set_sort_column(column_record.id, Gtk::SortType::SORT_ASCENDING);
tree_view.set_enable_search(true); //TODO: why does this not work in OS X?
tree_view.set_search_column(column_record.name);
tree_view.signal_row_activated().connect([this](const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column){ tree_view.signal_row_activated().connect([this](const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column){
INFO("Directory navigation"); INFO("Directory navigation");
auto iter = tree_store->get_iter(path); auto iter = tree_store->get_iter(path);
if (iter) { if (iter) {
Gtk::TreeModel::Row row = *iter; auto path_str=iter->get_value(column_record.path);
std::string upath = Glib::ustring(row[column_record.path]); if(path_str!="") {
boost::filesystem::path fs_path(upath); if (boost::filesystem::is_directory(boost::filesystem::path(path_str))) {
if (boost::filesystem::is_directory(fs_path)) {
tree_view.row_expanded(path) ? tree_view.collapse_row(path) : tree_view.expand_row(path, false); tree_view.row_expanded(path) ? tree_view.collapse_row(path) : tree_view.expand_row(path, false);
} else { } else {
std::stringstream sstm;
sstm << row[column_record.path];
if(on_row_activated) if(on_row_activated)
on_row_activated(sstm.str()); on_row_activated(path_str);
}
} }
} }
}); });
}
void Directories::open_folder(const boost::filesystem::path& dir_path) { tree_view.signal_test_expand_row().connect([this](const Gtk::TreeModel::iterator& iter, const Gtk::TreeModel::Path& path){
auto new_path=dir_path; if(iter->children().begin()->get_value(column_record.path)=="") {
INFO("Open folder"); update_mutex.lock();
if(new_path=="") { add_path(iter->get_value(column_record.path), *iter);
if(current_path=="") update_mutex.unlock();
return; }
new_path=current_path; return false;
});
tree_view.signal_row_collapsed().connect([this](const Gtk::TreeModel::iterator& iter, const Gtk::TreeModel::Path& path){
update_mutex.lock();
last_write_times.erase(iter->get_value(column_record.path));
update_mutex.unlock();
auto children=iter->children();
if(children) {
while(children) {
tree_store->erase(children.begin());
} }
auto child=tree_store->append(iter->children());
child->set_value(column_record.name, std::string("(empty)"));
}
});
std::vector<Gtk::TreeModel::Path> expanded_paths; update_dispatcher.connect([this](){
if(current_path==new_path) { update_mutex.lock();
tree_view.map_expanded_rows([&expanded_paths](Gtk::TreeView* tree_view, const Gtk::TreeModel::Path& path){ for(auto &path: update_paths) {
expanded_paths.emplace_back(path); if(last_write_times.count(path)>0)
add_path(path, last_write_times.at(path).first);
}
update_paths.clear();
update_mutex.unlock();
}); });
update_thread=std::thread([this](){
while(!stop_update_thread) {
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
update_mutex.lock();
if(update_paths.size()==0) {
for(auto it=last_write_times.begin();it!=last_write_times.end();) {
try {
if(boost::filesystem::exists(it->first)) { //Added for older boost versions (no exception thrown)
if(it->second.second<boost::filesystem::last_write_time(it->first)) {
update_paths.emplace_back(it->first);
}
it++;
}
else
it=last_write_times.erase(it);
} }
catch(const std::exception &e) {
it=last_write_times.erase(it);
}
}
if(update_paths.size()>0)
update_dispatcher();
}
update_mutex.unlock();
}
});
}
Directories::~Directories() {
stop_update_thread=true;
update_thread.join();
}
void Directories::open(const boost::filesystem::path& dir_path) {
if(dir_path=="")
return;
INFO("Open folder");
tree_store->clear(); tree_store->clear();
update_mutex.lock();
last_write_times.clear();
update_paths.clear();
update_mutex.unlock();
if(dir_path!="") cmake=std::unique_ptr<CMake>(new CMake(dir_path));
cmake=std::unique_ptr<CMake>(new CMake(new_path));
auto project=cmake->get_functions_parameters("project"); auto project=cmake->get_functions_parameters("project");
if(project.size()>0 && project[0].second.size()>0) if(project.size()>0 && project[0].second.size()>0)
tree_view.get_column(0)->set_title(project[0].second[0]); tree_view.get_column(0)->set_title(project[0].second[0]);
else else
tree_view.get_column(0)->set_title(""); tree_view.get_column(0)->set_title("");
add_paths(new_path, Gtk::TreeModel::Row(), 0); update_mutex.lock();
add_path(dir_path, Gtk::TreeModel::Row());
for(auto &path: expanded_paths) update_mutex.unlock();
tree_view.expand_row(path, false);
current_path=new_path; current_path=dir_path;
if(selected_path!="")
select_path(selected_path);
DEBUG("Folder opened"); DEBUG("Folder opened");
} }
void Directories::select_path(const boost::filesystem::path &path) { void Directories::update() {
update_mutex.lock();
for(auto &last_write_time: last_write_times) {
add_path(last_write_time.first, last_write_time.second.first);
}
update_mutex.unlock();
}
void Directories::select(const boost::filesystem::path &path) {
if(current_path=="")
return;
if(path.string().substr(0, current_path.string().size())!=current_path.string())
return;
std::list<boost::filesystem::path> paths;
boost::filesystem::path parent_path;
if(boost::filesystem::is_directory(path))
parent_path=path;
else
parent_path=path.parent_path();
paths.emplace_front(parent_path);
while(parent_path!=current_path) {
parent_path=parent_path.parent_path();
paths.emplace_front(parent_path);
}
for(auto &a_path: paths) {
tree_store->foreach_iter([this, &a_path](const Gtk::TreeModel::iterator& iter){
if(iter->get_value(column_record.path)==a_path.string()) {
update_mutex.lock();
add_path(a_path, *iter);
update_mutex.unlock();
return true;
}
return false;
});
}
tree_store->foreach_iter([this, &path](const Gtk::TreeModel::iterator& iter){ tree_store->foreach_iter([this, &path](const Gtk::TreeModel::iterator& iter){
if(iter->get_value(column_record.path)==path.string()) { if(iter->get_value(column_record.path)==path.string()) {
auto tree_path=Gtk::TreePath(iter); auto tree_path=Gtk::TreePath(iter);
tree_view.expand_to_path(tree_path); tree_view.expand_to_path(tree_path);
tree_view.set_cursor(tree_path); tree_view.set_cursor(tree_path);
selected_path=path;
return true; return true;
} }
return false; return false;
@ -106,37 +197,58 @@ bool Directories::ignored(std::string path) {
return false; return false;
} }
void Directories::add_paths(const boost::filesystem::path& dir_path, const Gtk::TreeModel::Row &parent, unsigned row_id) { void Directories::add_path(const boost::filesystem::path& dir_path, const Gtk::TreeModel::Row &parent) {
boost::filesystem::directory_iterator end_itr; last_write_times[dir_path.string()]={parent, boost::filesystem::last_write_time(dir_path)};
Gtk::TreeModel::Row child; std::unique_ptr<Gtk::TreeNodeChildren> children; //Gtk::TreeNodeChildren is missing default constructor...
Gtk::TreeModel::Row row; if(parent)
DEBUG(""); children=std::unique_ptr<Gtk::TreeNodeChildren>(new Gtk::TreeNodeChildren(parent.children()));
// Fill the treeview else
for(boost::filesystem::directory_iterator itr(dir_path);itr != end_itr;++itr) { children=std::unique_ptr<Gtk::TreeNodeChildren>(new Gtk::TreeNodeChildren(tree_store->children()));
if (!ignored(itr->path().filename().string())) { if(*children) {
if (boost::filesystem::is_directory(itr->status())) { if(children->begin()->get_value(column_record.path)=="")
if (boost::filesystem::canonical(itr->path()) > boost::filesystem::canonical(dir_path)) { // is child tree_store->erase(children->begin());
child = *(tree_store->append(parent.children())); }
std::string col_id("a"+itr->path().filename().string()); std::unordered_set<std::string> not_deleted;
child[column_record.id] = col_id; boost::filesystem::directory_iterator end_it;
child[column_record.name] = itr->path().filename().string(); for(boost::filesystem::directory_iterator it(dir_path);it!=end_it;it++) {
child[column_record.path] = itr->path().string(); auto filename=it->path().filename().string();
add_paths(itr->path(), child, row_id); if (!ignored(filename)) {
} else { bool already_added=false;
row = *(tree_store->append()); if(*children) {
std::string col_id("a"+itr->path().filename().string()); for(auto &child: *children) {
row[column_record.path] = itr->path().string(); if(child.get_value(column_record.name)==filename) {
row[column_record.id] = col_id; not_deleted.emplace(filename);
row[column_record.name] = itr->path().filename().string(); already_added=true;
add_paths(itr->path(), parent, row_id); break;
}
}
} }
} else { // is a file if(!already_added) {
child = *(tree_store->append(parent.children())); auto child = tree_store->append(*children);
std::string col_id("b"+itr->path().filename().string()); not_deleted.emplace(filename);
child[column_record.id] = col_id; child->set_value(column_record.name, filename);
child[column_record.name] = itr->path().filename().string(); child->set_value(column_record.path, it->path().string());
child[column_record.path] = itr->path().string(); if (boost::filesystem::is_directory(*it)) {
child->set_value(column_record.id, "a"+filename);
auto grandchild=tree_store->append(child->children());
grandchild->set_value(column_record.name, std::string("(empty)"));
}
else
child->set_value(column_record.id, "b"+filename);
}
}
}
if(*children) {
for(auto it=children->begin();it!=children->end();) {
if(not_deleted.count(it->get_value(column_record.name))==0) {
it=tree_store->erase(it);
}
else
it++;
} }
} }
if(!*children) {
auto child=tree_store->append(*children);
child->set_value(column_record.name, std::string("(empty)"));
} }
} }

24
src/directories.h

@ -6,6 +6,9 @@
#include <string> #include <string>
#include "boost/filesystem.hpp" #include "boost/filesystem.hpp"
#include "cmake.h" #include "cmake.h"
#include <thread>
#include <mutex>
#include <atomic>
class Directories : public Gtk::ScrolledWindow { class Directories : public Gtk::ScrolledWindow {
public: public:
@ -22,26 +25,33 @@ public:
add(name); add(name);
add(path); add(path);
} }
Gtk::TreeModelColumn<Glib::ustring> id; Gtk::TreeModelColumn<std::string> id;
Gtk::TreeModelColumn<Glib::ustring> name; Gtk::TreeModelColumn<std::string> name;
Gtk::TreeModelColumn<Glib::ustring> path; Gtk::TreeModelColumn<std::string> path;
}; };
Directories(); Directories();
void open_folder(const boost::filesystem::path& dir_path=""); ~Directories();
void select_path(const boost::filesystem::path &path); void open(const boost::filesystem::path& dir_path="");
void update();
void select(const boost::filesystem::path &path);
std::function<void(const std::string &file)> on_row_activated; std::function<void(const std::string &file)> on_row_activated;
std::unique_ptr<CMake> cmake; std::unique_ptr<CMake> cmake;
boost::filesystem::path current_path; boost::filesystem::path current_path;
private: private:
void add_paths(const boost::filesystem::path& dir_path, const Gtk::TreeModel::Row &row, unsigned depth); void add_path(const boost::filesystem::path& dir_path, const Gtk::TreeModel::Row &row);
bool ignored(std::string path); bool ignored(std::string path);
Gtk::TreeView tree_view; Gtk::TreeView tree_view;
Glib::RefPtr<Gtk::TreeStore> tree_store; Glib::RefPtr<Gtk::TreeStore> tree_store;
ColumnRecord column_record; ColumnRecord column_record;
boost::filesystem::path selected_path; std::unordered_map<std::string, std::pair<Gtk::TreeModel::Row, std::time_t> > last_write_times;
std::mutex update_mutex;
std::thread update_thread;
std::atomic<bool> stop_update_thread;
Glib::Dispatcher update_dispatcher;
std::vector<std::string> update_paths;
}; };
#endif // JUCI_DIRECTORIES_H_ #endif // JUCI_DIRECTORIES_H_

16
src/files.h

@ -7,7 +7,12 @@ const std::string configjson =
" },\n" " },\n"
" \"source\": {\n" " \"source\": {\n"
" \"style\": \"juci-light\", //Use \"\" for default style, and for instance juci-dark together with dark gtk_theme variant. Styles from normal gtksourceview install: classic, cobalt, kate, oblivion, solarized-dark, solarized-light, tango\n" " \"style\": \"juci-light\", //Use \"\" for default style, and for instance juci-dark together with dark gtk_theme variant. Styles from normal gtksourceview install: classic, cobalt, kate, oblivion, solarized-dark, solarized-light, tango\n"
" \"font\": \"Monospace\", //Use \"\" for default font, and for instance \"Monospace 12\" to also set size.\n" #ifdef __APPLE__
" \"font\": \"Menlo 11\", "
#else
" \"font\": \"Monospace\", "
#endif
"//Use \"\" for default font, and for instance \"Monospace 12\" to also set size.\n"
" \"clang_types\": {\n" " \"clang_types\": {\n"
" \"8\": \"def:function\",\n" " \"8\": \"def:function\",\n"
" \"21\": \"def:function\",\n" " \"21\": \"def:function\",\n"
@ -23,14 +28,16 @@ const std::string configjson =
" \"702\": \"def:statement\",\n" " \"702\": \"def:statement\",\n"
" \"705\": \"def:comment\"\n" " \"705\": \"def:comment\"\n"
" },\n" " },\n"
" \"tab_size\": 2,\n" " \"auto_tab_char_and_size\": true, //Use false to always use default tab char and size\n"
" \"tab_char\": \" \", //Use \"\\t\" for regular tab\n" " \"default_tab_char\": \" \", //Use \"\\t\" for regular tab\n"
" \"default_tab_size\": 2,\n"
" \"highlight_current_line\": true,\n" " \"highlight_current_line\": true,\n"
" \"show_line_numbers\": true\n" " \"show_line_numbers\": true\n"
" },\n" " },\n"
" \"keybindings\": {\n" " \"keybindings\": {\n"
" \"new_file\": \"<primary>n\",\n" " \"new_file\": \"<primary>n\",\n"
" \"open_folder\": \"<primary><alt>o\",\n" " \"new_folder\": \"<primary><shift>n\",\n"
" \"open_folder\": \"<primary><shift>o\",\n"
" \"open_file\": \"<primary>o\",\n" " \"open_file\": \"<primary>o\",\n"
" \"save\": \"<primary>s\",\n" " \"save\": \"<primary>s\",\n"
" \"save_as\": \"<primary><shift>s\",\n" " \"save_as\": \"<primary><shift>s\",\n"
@ -76,6 +83,7 @@ const std::string menuxml =
" <menubar name=\"MenuBar\">\n" " <menubar name=\"MenuBar\">\n"
" <menu action=\"FileMenu\">\n" " <menu action=\"FileMenu\">\n"
" <menuitem action=\"FileNewFile\"/>\n" " <menuitem action=\"FileNewFile\"/>\n"
" <menuitem action=\"FileNewFolder\"/>\n"
" <menu action=\"FileNewProject\">\n" " <menu action=\"FileNewProject\">\n"
" <menuitem action=\"FileNewProjectCpp\"/>\n" " <menuitem action=\"FileNewProjectCpp\"/>\n"
" </menu>\n" " </menu>\n"

2
src/juci.cc

@ -45,7 +45,7 @@ void app::on_activate() {
bool first_directory=true; bool first_directory=true;
for(auto &directory: directories) { for(auto &directory: directories) {
if(first_directory) { if(first_directory) {
window->directories.open_folder(directory); window->directories.open(directory);
first_directory=false; first_directory=false;
} }
else { else {

1
src/notebook.cc

@ -120,7 +120,6 @@ bool Notebook::save(int page) {
//TODO: recreate cmake even without directories open? //TODO: recreate cmake even without directories open?
if(view->file_path.filename()=="CMakeLists.txt") { if(view->file_path.filename()=="CMakeLists.txt") {
if(directories.cmake && directories.cmake->project_path!="" && view->file_path.string().substr(0, directories.cmake->project_path.string().size())==directories.cmake->project_path.string() && CMake::create_compile_commands(directories.cmake->project_path)) { if(directories.cmake && directories.cmake->project_path!="" && view->file_path.string().substr(0, directories.cmake->project_path.string().size())==directories.cmake->project_path.string() && CMake::create_compile_commands(directories.cmake->project_path)) {
directories.open_folder();
for(auto source_view: source_views) { for(auto source_view: source_views) {
if(auto source_clang_view=dynamic_cast<Source::ClangView*>(source_view)) { if(auto source_clang_view=dynamic_cast<Source::ClangView*>(source_view)) {
if(directories.cmake->project_path.string()==source_clang_view->project_path) { if(directories.cmake->project_path.string()==source_clang_view->project_path) {

164
src/source.cc

@ -4,7 +4,6 @@
#include <boost/timer/timer.hpp> #include <boost/timer/timer.hpp>
#include "logging.h" #include "logging.h"
#include <algorithm> #include <algorithm>
#include <regex>
#include "singletons.h" #include "singletons.h"
#include <gtksourceview/gtksource.h> #include <gtksourceview/gtksource.h>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
@ -75,6 +74,29 @@ Source::View::View(const boost::filesystem::path &file_path): file_path(file_pat
property_show_line_numbers() = Singleton::Config::source()->show_line_numbers; property_show_line_numbers() = Singleton::Config::source()->show_line_numbers;
if(Singleton::Config::source()->font.size()>0) if(Singleton::Config::source()->font.size()>0)
override_font(Pango::FontDescription(Singleton::Config::source()->font)); override_font(Pango::FontDescription(Singleton::Config::source()->font));
tab_char=Singleton::Config::source()->default_tab_char;
tab_size=Singleton::Config::source()->default_tab_size;
if(Singleton::Config::source()->auto_tab_char_and_size) {
auto tab_char_and_size=find_tab_char_and_size();
if(tab_char_and_size.first!=0) {
if(tab_char!=tab_char_and_size.first || tab_size!=tab_char_and_size.second) {
std::string tab_str;
if(tab_char_and_size.first==' ')
tab_str="<space>";
else
tab_str="<tab>";
Singleton::terminal()->print("Tab char and size for file "+file_path.string()+" set to: "+tab_str+", "+boost::lexical_cast<std::string>(tab_char_and_size.second)+".\n");
}
tab_char=tab_char_and_size.first;
tab_size=tab_char_and_size.second;
}
}
for(unsigned c=0;c<tab_size;c++)
tab+=tab_char;
tabs_regex=std::regex(std::string("^(")+tab_char+"*)(.*)$");
} }
void Source::View::search_occurrences_updated(GtkWidget* widget, GParamSpec* property, gpointer data) { void Source::View::search_occurrences_updated(GtkWidget* widget, GParamSpec* property, gpointer data) {
@ -151,11 +173,10 @@ void Source::View::replace_all(const std::string &replacement) {
void Source::View::paste() { void Source::View::paste() {
Gtk::Clipboard::get()->request_text([this](const Glib::ustring& text){ Gtk::Clipboard::get()->request_text([this](const Glib::ustring& text){
const std::regex spaces_regex(std::string("^(")+Singleton::Config::source()->tab_char+"*)(.*)$");
auto line=get_line_before_insert(); auto line=get_line_before_insert();
std::smatch sm; std::smatch sm;
std::string prefix_tabs; std::string prefix_tabs;
if(!get_buffer()->get_has_selection() && std::regex_match(line, sm, spaces_regex) && sm[2].str().size()==0) { if(!get_buffer()->get_has_selection() && std::regex_match(line, sm, tabs_regex) && sm[2].str().size()==0) {
prefix_tabs=sm[1].str(); prefix_tabs=sm[1].str();
Glib::ustring::size_type start_line=0; Glib::ustring::size_type start_line=0;
@ -177,7 +198,7 @@ void Source::View::paste() {
std::string line=text.substr(start_line, end_line-start_line); std::string line=text.substr(start_line, end_line-start_line);
size_t tabs=0; size_t tabs=0;
for(auto chr: line) { for(auto chr: line) {
if(chr==Singleton::Config::source()->tab_char) if(chr==tab_char)
tabs++; tabs++;
else else
break; break;
@ -260,21 +281,19 @@ string Source::View::get_line_before_insert() {
//Basic indentation //Basic indentation
bool Source::View::on_key_press_event(GdkEventKey* key) { bool Source::View::on_key_press_event(GdkEventKey* key) {
get_source_buffer()->begin_user_action(); get_source_buffer()->begin_user_action();
auto config=Singleton::Config::source();
const std::regex spaces_regex(std::string("^(")+config->tab_char+"*).*$");
//Indent as in next or previous line //Indent as in next or previous line
if(key->keyval==GDK_KEY_Return && key->state==0 && !get_buffer()->get_has_selection()) { if(key->keyval==GDK_KEY_Return && key->state==0 && !get_buffer()->get_has_selection()) {
auto insert_it=get_buffer()->get_insert()->get_iter(); auto insert_it=get_buffer()->get_insert()->get_iter();
int line_nr=insert_it.get_line(); int line_nr=insert_it.get_line();
auto line=get_line_before_insert(); auto line=get_line_before_insert();
std::smatch sm; std::smatch sm;
if(std::regex_match(line, sm, spaces_regex)) { if(std::regex_match(line, sm, tabs_regex)) {
if((line_nr+1)<get_buffer()->get_line_count()) { if((line_nr+1)<get_buffer()->get_line_count()) {
string next_line=get_line(line_nr+1); string next_line=get_line(line_nr+1);
auto line_end_iter=get_buffer()->get_iter_at_line(line_nr+1); auto line_end_iter=get_buffer()->get_iter_at_line(line_nr+1);
line_end_iter--; line_end_iter--;
std::smatch sm2; std::smatch sm2;
if(insert_it==line_end_iter && std::regex_match(next_line, sm2, spaces_regex)) { if(insert_it==line_end_iter && std::regex_match(next_line, sm2, tabs_regex)) {
if(sm2[1].str().size()>sm[1].str().size()) { if(sm2[1].str().size()>sm[1].str().size()) {
get_source_buffer()->insert_at_cursor("\n"+sm2[1].str()); get_source_buffer()->insert_at_cursor("\n"+sm2[1].str());
scroll_to(get_source_buffer()->get_insert()); scroll_to(get_source_buffer()->get_insert());
@ -297,7 +316,7 @@ bool Source::View::on_key_press_event(GdkEventKey* key) {
int line_end=selection_end.get_line(); int line_end=selection_end.get_line();
for(int line=line_start;line<=line_end;line++) { for(int line=line_start;line<=line_end;line++) {
Gtk::TextIter line_it = get_source_buffer()->get_iter_at_line(line); Gtk::TextIter line_it = get_source_buffer()->get_iter_at_line(line);
get_source_buffer()->insert(line_it, config->tab); get_source_buffer()->insert(line_it, tab);
} }
get_source_buffer()->end_user_action(); get_source_buffer()->end_user_action();
return true; return true;
@ -309,11 +328,11 @@ bool Source::View::on_key_press_event(GdkEventKey* key) {
int line_start=selection_start.get_line(); int line_start=selection_start.get_line();
int line_end=selection_end.get_line(); int line_end=selection_end.get_line();
unsigned indent_left_steps=config->tab_size; unsigned indent_left_steps=tab_size;
for(int line_nr=line_start;line_nr<=line_end;line_nr++) { for(int line_nr=line_start;line_nr<=line_end;line_nr++) {
string line=get_line(line_nr); string line=get_line(line_nr);
std::smatch sm; std::smatch sm;
if(std::regex_match(line, sm, spaces_regex) && sm[1].str().size()>0) { if(std::regex_match(line, sm, tabs_regex) && sm[1].str().size()>0) {
indent_left_steps=std::min(indent_left_steps, (unsigned)sm[1].str().size()); indent_left_steps=std::min(indent_left_steps, (unsigned)sm[1].str().size());
} }
else { else {
@ -339,12 +358,12 @@ bool Source::View::on_key_press_event(GdkEventKey* key) {
int line_nr=insert_it.get_line(); int line_nr=insert_it.get_line();
auto line=get_line_before_insert(); auto line=get_line_before_insert();
std::smatch sm; std::smatch sm;
if(std::regex_match(line, sm, spaces_regex) && sm[1].str().size()==line.size()) { if(std::regex_match(line, sm, tabs_regex) && sm[1].str().size()==line.size()) {
if((line_nr-1)>=0) { if((line_nr-1)>=0) {
string previous_line=get_line(line_nr-1); string previous_line=get_line(line_nr-1);
std::smatch sm2; std::smatch sm2;
if(std::regex_match(previous_line, sm2, spaces_regex)) { if(std::regex_match(previous_line, sm2, tabs_regex)) {
if(line.size()==sm2[1].str().size() || line.size()==sm2[1].str().size()+config->tab_size || line.size()==sm2[1].str().size()-config->tab_size) { if(line.size()==sm2[1].str().size() || line.size()==sm2[1].str().size()+tab_size || line.size()==sm2[1].str().size()-tab_size) {
auto previous_line_end_it=insert_it; auto previous_line_end_it=insert_it;
for(unsigned c=0;c<line.size();c++) for(unsigned c=0;c<line.size();c++)
previous_line_end_it--; previous_line_end_it--;
@ -355,9 +374,9 @@ bool Source::View::on_key_press_event(GdkEventKey* key) {
} }
} }
} }
if(line.size()>=config->tab_size) { if(line.size()>=tab_size) {
auto insert_minus_tab_it=insert_it; auto insert_minus_tab_it=insert_it;
for(unsigned c=0;c<config->tab_size;c++) for(unsigned c=0;c<tab_size;c++)
insert_minus_tab_it--; insert_minus_tab_it--;
get_source_buffer()->erase(insert_minus_tab_it, insert_it); get_source_buffer()->erase(insert_minus_tab_it, insert_it);
get_source_buffer()->end_user_action(); get_source_buffer()->end_user_action();
@ -371,6 +390,58 @@ bool Source::View::on_key_press_event(GdkEventKey* key) {
return stop; return stop;
} }
std::pair<char, unsigned> Source::View::find_tab_char_and_size() {
const std::regex indent_regex("^([ \t]+).*$");
auto size=get_buffer()->get_line_count();
std::unordered_map<char, size_t> tab_chars;
std::unordered_map<unsigned, size_t> tab_sizes;
unsigned last_tab_size=0;
for(int c=0;c<size;c++) {
auto line=get_line(c);
std::smatch sm;
if(std::regex_match(line, sm, indent_regex)) {
auto str=sm[1].str();
long tab_diff=abs(static_cast<long>(str.size()-last_tab_size));
if(tab_diff>0) {
unsigned tab_diff_unsigned=static_cast<unsigned>(tab_diff);
auto it_size=tab_sizes.find(tab_diff_unsigned);
if(it_size!=tab_sizes.end())
it_size->second++;
else
tab_sizes[tab_diff_unsigned]=1;
}
last_tab_size=str.size();
if(str.size()>0) {
auto it_char=tab_chars.find(str[0]);
if(it_char!=tab_chars.end())
it_char->second++;
else
tab_chars[str[0]]=1;
}
}
}
char found_tab_char=0;
size_t occurences=0;
for(auto &tab_char: tab_chars) {
if(tab_char.second>occurences) {
found_tab_char=tab_char.first;
occurences=tab_char.second;
}
}
unsigned found_tab_size=0;
occurences=0;
for(auto &tab_size: tab_sizes) {
if(tab_size.second>occurences) {
found_tab_size=tab_size.first;
occurences=tab_size.second;
}
}
return {found_tab_char, found_tab_size};
}
///////////////////// /////////////////////
//// GenericView //// //// GenericView ////
///////////////////// /////////////////////
@ -509,6 +580,10 @@ Source::View(file_path), project_path(project_path) {
}); });
get_buffer()->signal_mark_set().connect(sigc::mem_fun(*this, &Source::ClangViewParse::on_mark_set), false); get_buffer()->signal_mark_set().connect(sigc::mem_fun(*this, &Source::ClangViewParse::on_mark_set), false);
bracket_regex=std::regex(std::string("^(")+tab_char+"*).*\\{ *$");
no_bracket_statement_regex=std::regex(std::string("^(")+tab_char+"*)(if|for|else if|catch|while) *\\(.*[^;}] *$");
no_bracket_no_para_statement_regex=std::regex(std::string("^(")+tab_char+"*)(else|try|do) *$");
} }
void Source::ClangViewParse::init_parse() { void Source::ClangViewParse::init_parse() {
@ -658,8 +733,24 @@ void Source::ClangViewParse::update_diagnostics() {
auto diagnostics=clang_tu->get_diagnostics(); auto diagnostics=clang_tu->get_diagnostics();
for(auto &diagnostic: diagnostics) { for(auto &diagnostic: diagnostics) {
if(diagnostic.path==file_path.string()) { if(diagnostic.path==file_path.string()) {
auto start=get_buffer()->get_iter_at_line_index(diagnostic.offsets.first.line-1, diagnostic.offsets.first.index-1); auto start_line=get_line(diagnostic.offsets.first.line-1); //index is sometimes off the line
auto end=get_buffer()->get_iter_at_line_index(diagnostic.offsets.second.line-1, diagnostic.offsets.second.index-1); auto start_line_index=diagnostic.offsets.first.index-1;
if(start_line_index>=start_line.size()) {
if(start_line.size()==0)
start_line_index=0;
else
start_line_index=start_line.size()-1;
}
auto end_line=get_line(diagnostic.offsets.second.line-1); //index is sometimes off the line
auto end_line_index=diagnostic.offsets.second.index-1;
if(end_line_index>=end_line.size()) {
if(end_line.size()==0)
end_line_index=0;
else
end_line_index=end_line.size()-1;
}
auto start=get_buffer()->get_iter_at_line_index(diagnostic.offsets.first.line-1, start_line_index);
auto end=get_buffer()->get_iter_at_line_index(diagnostic.offsets.second.line-1, end_line_index);
std::string diagnostic_tag_name; std::string diagnostic_tag_name;
if(diagnostic.severity<=CXDiagnostic_Warning) if(diagnostic.severity<=CXDiagnostic_Warning)
diagnostic_tag_name="def:warning"; diagnostic_tag_name="def:warning";
@ -765,11 +856,6 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) {
return Source::View::on_key_press_event(key); return Source::View::on_key_press_event(key);
} }
get_source_buffer()->begin_user_action(); get_source_buffer()->begin_user_action();
auto config=Singleton::Config::source();
const std::regex bracket_regex(std::string("^(")+config->tab_char+"*).*\\{ *$");
const std::regex no_bracket_statement_regex(std::string("^(")+config->tab_char+"*)(if|for|else if|catch|while) *\\(.*[^;}] *$");
const std::regex no_bracket_no_para_statement_regex(std::string("^(")+config->tab_char+"*)(else|try|do) *$");
const std::regex spaces_regex(std::string("^(")+config->tab_char+"*).*$");
//Indent depending on if/else/etc and brackets //Indent depending on if/else/etc and brackets
if(key->keyval==GDK_KEY_Return && key->state==0) { if(key->keyval==GDK_KEY_Return && key->state==0) {
@ -780,18 +866,18 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) {
if((line_nr+1)<get_source_buffer()->get_line_count()) { if((line_nr+1)<get_source_buffer()->get_line_count()) {
string next_line=get_line(line_nr+1); string next_line=get_line(line_nr+1);
std::smatch sm2; std::smatch sm2;
if(std::regex_match(next_line, sm2, spaces_regex)) { if(std::regex_match(next_line, sm2, tabs_regex)) {
if(sm2[1].str()==sm[1].str()+config->tab) { if(sm2[1].str()==sm[1].str()+tab) {
get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+config->tab); get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+tab);
scroll_to(get_source_buffer()->get_insert()); scroll_to(get_source_buffer()->get_insert());
get_source_buffer()->end_user_action(); get_source_buffer()->end_user_action();
return true; return true;
} }
} }
if(next_line!=sm[1].str()+"}") { if(next_line!=sm[1].str()+"}") {
get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+config->tab+"\n"+sm[1].str()+"}"); get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+tab+"\n"+sm[1].str()+"}");
auto insert_it = get_source_buffer()->get_insert()->get_iter(); auto insert_it = get_source_buffer()->get_insert()->get_iter();
for(size_t c=0;c<config->tab_size+sm[1].str().size();c++) for(size_t c=0;c<sm[1].str().size()+2;c++)
insert_it--; insert_it--;
scroll_to(get_source_buffer()->get_insert()); scroll_to(get_source_buffer()->get_insert());
get_source_buffer()->place_cursor(insert_it); get_source_buffer()->place_cursor(insert_it);
@ -799,7 +885,7 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) {
return true; return true;
} }
else { else {
get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+config->tab); get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+tab);
scroll_to(get_source_buffer()->get_insert()); scroll_to(get_source_buffer()->get_insert());
get_source_buffer()->end_user_action(); get_source_buffer()->end_user_action();
return true; return true;
@ -807,21 +893,21 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) {
} }
} }
else if(std::regex_match(line, sm, no_bracket_statement_regex)) { else if(std::regex_match(line, sm, no_bracket_statement_regex)) {
get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+config->tab); get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+tab);
scroll_to(get_source_buffer()->get_insert()); scroll_to(get_source_buffer()->get_insert());
get_source_buffer()->end_user_action(); get_source_buffer()->end_user_action();
return true; return true;
} }
else if(std::regex_match(line, sm, no_bracket_no_para_statement_regex)) { else if(std::regex_match(line, sm, no_bracket_no_para_statement_regex)) {
get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+config->tab); get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+tab);
scroll_to(get_source_buffer()->get_insert()); scroll_to(get_source_buffer()->get_insert());
get_source_buffer()->end_user_action(); get_source_buffer()->end_user_action();
return true; return true;
} }
else if(std::regex_match(line, sm, spaces_regex)) { else if(std::regex_match(line, sm, tabs_regex)) {
std::smatch sm2; std::smatch sm2;
size_t line_nr=get_source_buffer()->get_insert()->get_iter().get_line(); size_t line_nr=get_source_buffer()->get_insert()->get_iter().get_line();
if(line_nr>0 && sm[1].str().size()>=config->tab_size) { if(line_nr>0 && sm[1].str().size()>=tab_size) {
string previous_line=get_line(line_nr-1); string previous_line=get_line(line_nr-1);
if(!std::regex_match(previous_line, sm2, bracket_regex)) { if(!std::regex_match(previous_line, sm2, bracket_regex)) {
if(std::regex_match(previous_line, sm2, no_bracket_statement_regex)) { if(std::regex_match(previous_line, sm2, no_bracket_statement_regex)) {
@ -843,23 +929,25 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) {
//Indent left when writing } on a new line //Indent left when writing } on a new line
else if(key->keyval==GDK_KEY_braceright) { else if(key->keyval==GDK_KEY_braceright) {
string line=get_line_before_insert(); string line=get_line_before_insert();
if(line.size()>=config->tab_size) { if(line.size()>=tab_size) {
for(auto c: line) { for(auto c: line) {
if(c!=config->tab_char) { if(c!=tab_char) {
get_source_buffer()->insert_at_cursor("}");
get_source_buffer()->end_user_action(); get_source_buffer()->end_user_action();
return Source::View::on_key_press_event(key); return true;
} }
} }
Gtk::TextIter insert_it = get_source_buffer()->get_insert()->get_iter(); Gtk::TextIter insert_it = get_source_buffer()->get_insert()->get_iter();
Gtk::TextIter line_it = get_source_buffer()->get_iter_at_line(insert_it.get_line()); Gtk::TextIter line_it = get_source_buffer()->get_iter_at_line(insert_it.get_line());
Gtk::TextIter line_plus_it=line_it; Gtk::TextIter line_plus_it=line_it;
for(unsigned c=0;c<config->tab_size;c++) for(unsigned c=0;c<tab_size;c++)
line_plus_it++; line_plus_it++;
get_source_buffer()->erase(line_it, line_plus_it); get_source_buffer()->erase(line_it, line_plus_it);
} }
get_source_buffer()->insert_at_cursor("}");
get_source_buffer()->end_user_action(); get_source_buffer()->end_user_action();
return Source::View::on_key_press_event(key); return true;
} }
get_source_buffer()->end_user_action(); get_source_buffer()->end_user_action();

17
src/source.h

@ -14,6 +14,7 @@
#include "tooltips.h" #include "tooltips.h"
#include "selectiondialog.h" #include "selectiondialog.h"
#include <set> #include <set>
#include <regex>
namespace Source { namespace Source {
Glib::RefPtr<Gsv::Language> guess_language(const boost::filesystem::path &file_path); Glib::RefPtr<Gsv::Language> guess_language(const boost::filesystem::path &file_path);
@ -22,9 +23,9 @@ namespace Source {
public: public:
std::string style; std::string style;
std::string font; std::string font;
unsigned tab_size; bool auto_tab_char_and_size;
char tab_char; char default_tab_char;
std::string tab; unsigned default_tab_size;
bool highlight_current_line; bool highlight_current_line;
bool show_line_numbers; bool show_line_numbers;
std::unordered_map<std::string, std::string> clang_types; std::unordered_map<std::string, std::string> clang_types;
@ -79,6 +80,12 @@ namespace Source {
std::string get_line_before_insert(); std::string get_line_before_insert();
bool on_key_press_event(GdkEventKey* key); bool on_key_press_event(GdkEventKey* key);
std::pair<char, unsigned> find_tab_char_and_size();
unsigned tab_size;
char tab_char;
std::string tab;
std::regex tabs_regex;
private: private:
GtkSourceSearchContext *search_context; GtkSourceSearchContext *search_context;
GtkSourceSearchSettings *search_settings; GtkSourceSearchSettings *search_settings;
@ -109,6 +116,10 @@ namespace Source {
std::shared_ptr<Terminal::InProgress> parsing_in_progress; std::shared_ptr<Terminal::InProgress> parsing_in_progress;
std::thread parse_thread; std::thread parse_thread;
std::atomic<bool> parse_thread_stop; std::atomic<bool> parse_thread_stop;
std::regex bracket_regex;
std::regex no_bracket_statement_regex;
std::regex no_bracket_no_para_statement_regex;
private: private:
std::map<std::string, std::string> get_buffer_map() const; std::map<std::string, std::string> get_buffer_map() const;
// inits the syntax highligthing on file open // inits the syntax highligthing on file open

153
src/window.cc

@ -91,7 +91,7 @@ Window::Window() : box(Gtk::ORIENTATION_VERTICAL), notebook(directories), compil
if(auto menu_item=dynamic_cast<Gtk::MenuItem*>(menu.ui_manager->get_widget("/MenuBar/SourceMenu/SourceRename"))) if(auto menu_item=dynamic_cast<Gtk::MenuItem*>(menu.ui_manager->get_widget("/MenuBar/SourceMenu/SourceRename")))
menu_item->set_sensitive((bool)notebook.get_current_view()->rename_similar_tokens); menu_item->set_sensitive((bool)notebook.get_current_view()->rename_similar_tokens);
directories.select_path(notebook.get_current_view()->file_path); directories.select(notebook.get_current_view()->file_path);
Singleton::status()->set_text(notebook.get_current_view()->status); Singleton::status()->set_text(notebook.get_current_view()->status);
} }
@ -100,10 +100,6 @@ Window::Window() : box(Gtk::ORIENTATION_VERTICAL), notebook(directories), compil
entry_box.hide(); entry_box.hide();
}); });
compile_success.connect([this](){
directories.open_folder();
});
INFO("Window created"); INFO("Window created");
} // Window constructor } // Window constructor
@ -112,20 +108,23 @@ void Window::create_menu() {
menu.action_group->add(Gtk::Action::create("FileQuit", "Quit juCi++"), Gtk::AccelKey(menu.key_map["quit"]), [this]() { menu.action_group->add(Gtk::Action::create("FileQuit", "Quit juCi++"), Gtk::AccelKey(menu.key_map["quit"]), [this]() {
hide(); hide();
}); });
menu.action_group->add(Gtk::Action::create("FileNewFile", "New file"), Gtk::AccelKey(menu.key_map["new_file"]), [this]() { menu.action_group->add(Gtk::Action::create("FileNewFile", "New File"), Gtk::AccelKey(menu.key_map["new_file"]), [this]() {
new_file_entry(); new_file_dialog();
});
menu.action_group->add(Gtk::Action::create("FileNewFolder", "New Folder"), Gtk::AccelKey(menu.key_map["new_folder"]), [this]() {
new_folder_dialog();
}); });
menu.action_group->add(Gtk::Action::create("FileNewProject", "New Project")); menu.action_group->add(Gtk::Action::create("FileNewProject", "New Project"));
menu.action_group->add(Gtk::Action::create("FileNewProjectCpp", "C++"), [this]() { menu.action_group->add(Gtk::Action::create("FileNewProjectCpp", "C++"), [this]() {
new_cpp_project_dialog(); new_cpp_project_dialog();
}); });
menu.action_group->add(Gtk::Action::create("FileOpenFile", "Open file"), Gtk::AccelKey(menu.key_map["open_file"]), [this]() { menu.action_group->add(Gtk::Action::create("FileOpenFile", "Open File"), Gtk::AccelKey(menu.key_map["open_file"]), [this]() {
open_file_dialog(); open_file_dialog();
}); });
menu.action_group->add(Gtk::Action::create("FileOpenFolder", "Open folder"), Gtk::AccelKey(menu.key_map["open_folder"]), [this]() { menu.action_group->add(Gtk::Action::create("FileOpenFolder", "Open Folder"), Gtk::AccelKey(menu.key_map["open_folder"]), [this]() {
open_folder_dialog(); open_folder_dialog();
}); });
menu.action_group->add(Gtk::Action::create("FileSaveAs", "Save as"), Gtk::AccelKey(menu.key_map["save_as"]), [this]() { menu.action_group->add(Gtk::Action::create("FileSaveAs", "Save As"), Gtk::AccelKey(menu.key_map["save_as"]), [this]() {
save_file_dialog(); save_file_dialog();
}); });
@ -178,17 +177,17 @@ void Window::create_menu() {
INFO("Done Redo"); INFO("Done Redo");
}); });
menu.action_group->add(Gtk::Action::create("SourceGotoLine", "Go to line"), Gtk::AccelKey(menu.key_map["source_goto_line"]), [this]() { menu.action_group->add(Gtk::Action::create("SourceGotoLine", "Go to Line"), Gtk::AccelKey(menu.key_map["source_goto_line"]), [this]() {
goto_line_entry(); goto_line_entry();
}); });
menu.action_group->add(Gtk::Action::create("SourceCenterCursor", "Center cursor"), Gtk::AccelKey(menu.key_map["source_center_cursor"]), [this]() { menu.action_group->add(Gtk::Action::create("SourceCenterCursor", "Center Cursor"), Gtk::AccelKey(menu.key_map["source_center_cursor"]), [this]() {
if(notebook.get_current_page()!=-1) { if(notebook.get_current_page()!=-1) {
while(gtk_events_pending()) while(gtk_events_pending())
gtk_main_iteration(); gtk_main_iteration();
notebook.get_current_view()->scroll_to(notebook.get_current_view()->get_buffer()->get_insert(), 0.0, 1.0, 0.5); notebook.get_current_view()->scroll_to(notebook.get_current_view()->get_buffer()->get_insert(), 0.0, 1.0, 0.5);
} }
}); });
menu.action_group->add(Gtk::Action::create("SourceGotoDeclaration", "Go to declaration"), Gtk::AccelKey(menu.key_map["source_goto_declaration"]), [this]() { menu.action_group->add(Gtk::Action::create("SourceGotoDeclaration", "Go to Declaration"), Gtk::AccelKey(menu.key_map["source_goto_declaration"]), [this]() {
if(notebook.get_current_page()!=-1) { if(notebook.get_current_page()!=-1) {
if(notebook.get_current_view()->get_declaration_location) { if(notebook.get_current_view()->get_declaration_location) {
auto location=notebook.get_current_view()->get_declaration_location(); auto location=notebook.get_current_view()->get_declaration_location();
@ -202,7 +201,7 @@ void Window::create_menu() {
} }
} }
}); });
menu.action_group->add(Gtk::Action::create("SourceGotoMethod", "Go to method"), Gtk::AccelKey(menu.key_map["source_goto_method"]), [this]() { menu.action_group->add(Gtk::Action::create("SourceGotoMethod", "Go to Method"), Gtk::AccelKey(menu.key_map["source_goto_method"]), [this]() {
if(notebook.get_current_page()!=-1) { if(notebook.get_current_page()!=-1) {
if(notebook.get_current_view()->goto_method) { if(notebook.get_current_view()->goto_method) {
notebook.get_current_view()->goto_method(); notebook.get_current_view()->goto_method();
@ -213,11 +212,10 @@ void Window::create_menu() {
rename_token_entry(); rename_token_entry();
}); });
menu.action_group->add(Gtk::Action::create("ProjectCompileAndRun", "Compile And Run"), Gtk::AccelKey(menu.key_map["compile_and_run"]), [this]() { menu.action_group->add(Gtk::Action::create("ProjectCompileAndRun", "Compile and Run"), Gtk::AccelKey(menu.key_map["compile_and_run"]), [this]() {
if(notebook.get_current_page()==-1 || compiling) if(notebook.get_current_page()==-1 || compiling)
return; return;
CMake cmake(notebook.get_current_view()->file_path); CMake cmake(notebook.get_current_view()->file_path);
directories.open_folder();
auto executables = cmake.get_functions_parameters("add_executable"); auto executables = cmake.get_functions_parameters("add_executable");
boost::filesystem::path executable_path; boost::filesystem::path executable_path;
if(executables.size()>0 && executables[0].second.size()>0) { if(executables.size()>0 && executables[0].second.size()>0) {
@ -233,7 +231,6 @@ void Window::create_menu() {
Singleton::terminal()->async_execute(Singleton::Config::terminal()->make_command, cmake.project_path, [this, executable_path, project_path](int exit_code){ Singleton::terminal()->async_execute(Singleton::Config::terminal()->make_command, cmake.project_path, [this, executable_path, project_path](int exit_code){
compiling=false; compiling=false;
if(exit_code==EXIT_SUCCESS) { if(exit_code==EXIT_SUCCESS) {
compile_success();
//TODO: Windows... //TODO: Windows...
auto executable_path_spaces_fixed=executable_path.string(); auto executable_path_spaces_fixed=executable_path.string();
char last_char=0; char last_char=0;
@ -261,15 +258,12 @@ void Window::create_menu() {
if(notebook.get_current_page()==-1 || compiling) if(notebook.get_current_page()==-1 || compiling)
return; return;
CMake cmake(notebook.get_current_view()->file_path); CMake cmake(notebook.get_current_view()->file_path);
directories.open_folder();
if(cmake.project_path!="") { if(cmake.project_path!="") {
compiling=true; compiling=true;
Singleton::terminal()->print("Compiling project "+cmake.project_path.string()+"\n"); Singleton::terminal()->print("Compiling project "+cmake.project_path.string()+"\n");
//TODO: Windows... //TODO: Windows...
Singleton::terminal()->async_execute(Singleton::Config::terminal()->make_command, cmake.project_path, [this](int exit_code){ Singleton::terminal()->async_execute(Singleton::Config::terminal()->make_command, cmake.project_path, [this](int exit_code){
compiling=false; compiling=false;
if(exit_code==EXIT_SUCCESS)
compile_success();
}); });
} }
}); });
@ -298,7 +292,7 @@ void Window::create_menu() {
Singleton::terminal()->kill_last_async_execute(true); Singleton::terminal()->kill_last_async_execute(true);
}); });
menu.action_group->add(Gtk::Action::create("WindowCloseTab", "Close tab"), Gtk::AccelKey(menu.key_map["close_tab"]), [this]() { menu.action_group->add(Gtk::Action::create("WindowCloseTab", "Close Tab"), Gtk::AccelKey(menu.key_map["close_tab"]), [this]() {
notebook.close_current_page(); notebook.close_current_page();
}); });
add_accel_group(menu.ui_manager->get_accel_group()); add_accel_group(menu.ui_manager->get_accel_group());
@ -355,35 +349,62 @@ void Window::hide() {
Gtk::Window::hide(); Gtk::Window::hide();
} }
void Window::new_file_entry() { void Window::new_file_dialog() {
entry_box.clear(); Gtk::FileChooserDialog dialog("Please create a new file", Gtk::FILE_CHOOSER_ACTION_SAVE);
entry_box.entries.emplace_back("untitled", [this](const std::string& content){ if(directories.current_path!="")
std::string filename=content; gtk_file_chooser_set_current_folder((GtkFileChooser*)dialog.gobj(), directories.current_path.string().c_str());
if(filename!="") { else
if(directories.current_path!="" && !boost::filesystem::path(filename).is_absolute()) gtk_file_chooser_set_current_folder((GtkFileChooser*)dialog.gobj(), boost::filesystem::current_path().string().c_str());
filename=directories.current_path.string()+"/"+filename; dialog.set_transient_for(*this);
boost::filesystem::path p(filename); dialog.set_position(Gtk::WindowPosition::WIN_POS_CENTER_ALWAYS);
if(boost::filesystem::exists(p)) { dialog.add_button("Cancel", Gtk::RESPONSE_CANCEL);
Singleton::terminal()->print("Error: "+p.string()+" already exists.\n"); dialog.add_button("Save", Gtk::RESPONSE_OK);
int result = dialog.run();
if(result==Gtk::RESPONSE_OK) {
boost::filesystem::path path = dialog.get_filename();
if(path!="") {
if(boost::filesystem::exists(path)) {
Singleton::terminal()->print("Error: "+path.string()+" already exists.\n");
} }
else { else {
if(juci::filesystem::write(p)) { if(juci::filesystem::write(path)) {
if(directories.current_path!="") if(directories.current_path!="")
directories.open_folder(); directories.update();
notebook.open(boost::filesystem::canonical(p).string()); notebook.open(path.string());
Singleton::terminal()->print("New file "+p.string()+" created.\n"); Singleton::terminal()->print("New file "+path.string()+" created.\n");
} }
else else
Singleton::terminal()->print("Error: could not create new file "+p.string()+".\n"); Singleton::terminal()->print("Error: could not create new file "+path.string()+".\n");
} }
} }
entry_box.hide(); }
}); }
auto entry_it=entry_box.entries.begin();
entry_box.buttons.emplace_back("Create file", [this, entry_it](){ void Window::new_folder_dialog() {
entry_it->activate(); auto time_now=std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
}); Gtk::FileChooserDialog dialog("Please create a new folder", Gtk::FILE_CHOOSER_ACTION_CREATE_FOLDER);
entry_box.show(); if(directories.current_path!="")
gtk_file_chooser_set_current_folder((GtkFileChooser*)dialog.gobj(), directories.current_path.string().c_str());
else
gtk_file_chooser_set_current_folder((GtkFileChooser*)dialog.gobj(), boost::filesystem::current_path().string().c_str());
dialog.set_transient_for(*this);
dialog.set_position(Gtk::WindowPosition::WIN_POS_CENTER_ALWAYS);
dialog.add_button("Cancel", Gtk::RESPONSE_CANCEL);
dialog.add_button("Create", Gtk::RESPONSE_OK);
int result = dialog.run();
if(result==Gtk::RESPONSE_OK) {
boost::filesystem::path path=dialog.get_filename();
if(boost::filesystem::last_write_time(path)>=time_now) {
if(directories.current_path!="")
directories.update();
Singleton::terminal()->print("New folder "+path.string()+" created.\n");
}
else
Singleton::terminal()->print("Error: "+path.string()+" already exists.\n");
directories.select(path);
}
} }
void Window::new_cpp_project_dialog() { void Window::new_cpp_project_dialog() {
@ -393,9 +414,9 @@ void Window::new_cpp_project_dialog() {
else else
gtk_file_chooser_set_current_folder((GtkFileChooser*)dialog.gobj(), boost::filesystem::current_path().string().c_str()); gtk_file_chooser_set_current_folder((GtkFileChooser*)dialog.gobj(), boost::filesystem::current_path().string().c_str());
dialog.set_transient_for(*this); dialog.set_transient_for(*this);
dialog.set_position(Gtk::WindowPosition::WIN_POS_CENTER_ALWAYS);
dialog.add_button("_Cancel", Gtk::RESPONSE_CANCEL); dialog.add_button("Cancel", Gtk::RESPONSE_CANCEL);
dialog.add_button("Select", Gtk::RESPONSE_OK); dialog.add_button("Create", Gtk::RESPONSE_OK);
int result = dialog.run(); int result = dialog.run();
if(result==Gtk::RESPONSE_OK) { if(result==Gtk::RESPONSE_OK) {
@ -420,7 +441,7 @@ void Window::new_cpp_project_dialog() {
std::string cmakelists="cmake_minimum_required(VERSION 2.8)\n\nproject("+project_name+")\n\nset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -std=c++1y -Wall\")\n\nadd_executable("+project_name+" main.cpp)\n"; std::string cmakelists="cmake_minimum_required(VERSION 2.8)\n\nproject("+project_name+")\n\nset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -std=c++1y -Wall\")\n\nadd_executable("+project_name+" main.cpp)\n";
std::string cpp_main="#include <iostream>\n\nusing namespace std;\n\nint main() {\n cout << \"Hello World!\" << endl;\n\n return 0;\n}\n"; std::string cpp_main="#include <iostream>\n\nusing namespace std;\n\nint main() {\n cout << \"Hello World!\" << endl;\n\n return 0;\n}\n";
if(juci::filesystem::write(cmakelists_path, cmakelists) && juci::filesystem::write(cpp_main_path, cpp_main)) { if(juci::filesystem::write(cmakelists_path, cmakelists) && juci::filesystem::write(cpp_main_path, cpp_main)) {
directories.open_folder(project_path); directories.open(project_path);
notebook.open(cpp_main_path); notebook.open(cpp_main_path);
Singleton::terminal()->print("C++ project "+project_name+" created.\n"); Singleton::terminal()->print("C++ project "+project_name+" created.\n");
} }
@ -436,15 +457,15 @@ void Window::open_folder_dialog() {
else else
gtk_file_chooser_set_current_folder((GtkFileChooser*)dialog.gobj(), boost::filesystem::current_path().string().c_str()); gtk_file_chooser_set_current_folder((GtkFileChooser*)dialog.gobj(), boost::filesystem::current_path().string().c_str());
dialog.set_transient_for(*this); dialog.set_transient_for(*this);
//Add response buttons the the dialog: dialog.set_position(Gtk::WindowPosition::WIN_POS_CENTER_ALWAYS);
dialog.add_button("_Cancel", Gtk::RESPONSE_CANCEL); dialog.add_button("Cancel", Gtk::RESPONSE_CANCEL);
dialog.add_button("Select", Gtk::RESPONSE_OK); dialog.add_button("Open", Gtk::RESPONSE_OK);
int result = dialog.run(); int result = dialog.run();
if(result==Gtk::RESPONSE_OK) { if(result==Gtk::RESPONSE_OK) {
std::string project_path=dialog.get_filename(); std::string project_path=dialog.get_filename();
directories.open_folder(project_path); directories.open(project_path);
} }
} }
@ -456,28 +477,8 @@ void Window::open_file_dialog() {
gtk_file_chooser_set_current_folder((GtkFileChooser*)dialog.gobj(), boost::filesystem::current_path().string().c_str()); gtk_file_chooser_set_current_folder((GtkFileChooser*)dialog.gobj(), boost::filesystem::current_path().string().c_str());
dialog.set_transient_for(*this); dialog.set_transient_for(*this);
dialog.set_position(Gtk::WindowPosition::WIN_POS_CENTER_ALWAYS); dialog.set_position(Gtk::WindowPosition::WIN_POS_CENTER_ALWAYS);
dialog.add_button("Cancel", Gtk::RESPONSE_CANCEL);
//Add response buttons the the dialog: dialog.add_button("Open", Gtk::RESPONSE_OK);
dialog.add_button("_Cancel", Gtk::RESPONSE_CANCEL);
dialog.add_button("_Open", Gtk::RESPONSE_OK);
//Add filters, so that only certain file types can be selected:
Glib::RefPtr<Gtk::FileFilter> filter_text = Gtk::FileFilter::create();
filter_text->set_name("Text files");
filter_text->add_mime_type("text/plain");
dialog.add_filter(filter_text);
Glib::RefPtr<Gtk::FileFilter> filter_cpp = Gtk::FileFilter::create();
filter_cpp->set_name("C/C++ files");
filter_cpp->add_mime_type("text/x-c");
filter_cpp->add_mime_type("text/x-c++");
filter_cpp->add_mime_type("text/x-c-header");
dialog.add_filter(filter_cpp);
Glib::RefPtr<Gtk::FileFilter> filter_any = Gtk::FileFilter::create();
filter_any->set_name("Any files");
filter_any->add_pattern("*");
dialog.add_filter(filter_any);
int result = dialog.run(); int result = dialog.run();
@ -494,8 +495,8 @@ void Window::save_file_dialog() {
Gtk::FileChooserDialog dialog(*this, "Please choose a file", Gtk::FILE_CHOOSER_ACTION_SAVE); Gtk::FileChooserDialog dialog(*this, "Please choose a file", Gtk::FILE_CHOOSER_ACTION_SAVE);
gtk_file_chooser_set_filename((GtkFileChooser*)dialog.gobj(), notebook.get_current_view()->file_path.c_str()); gtk_file_chooser_set_filename((GtkFileChooser*)dialog.gobj(), notebook.get_current_view()->file_path.c_str());
dialog.set_position(Gtk::WindowPosition::WIN_POS_CENTER_ALWAYS); dialog.set_position(Gtk::WindowPosition::WIN_POS_CENTER_ALWAYS);
dialog.add_button("_Cancel", Gtk::RESPONSE_CANCEL); dialog.add_button("Cancel", Gtk::RESPONSE_CANCEL);
dialog.add_button("_Save", Gtk::RESPONSE_OK); dialog.add_button("Save", Gtk::RESPONSE_OK);
int result = dialog.run(); int result = dialog.run();
if(result==Gtk::RESPONSE_OK) { if(result==Gtk::RESPONSE_OK) {
@ -506,7 +507,7 @@ void Window::save_file_dialog() {
file << notebook.get_current_view()->get_buffer()->get_text(); file << notebook.get_current_view()->get_buffer()->get_text();
file.close(); file.close();
if(directories.current_path!="") if(directories.current_path!="")
directories.open_folder(); directories.update();
notebook.open(path); notebook.open(path);
Singleton::terminal()->print("File saved to: " + notebook.get_current_view()->file_path.string()+"\n"); Singleton::terminal()->print("File saved to: " + notebook.get_current_view()->file_path.string()+"\n");
} }

4
src/window.h

@ -36,11 +36,11 @@ private:
EntryBox entry_box; EntryBox entry_box;
Menu menu; Menu menu;
std::atomic<bool> compiling; std::atomic<bool> compiling;
Glib::Dispatcher compile_success;
void create_menu(); void create_menu();
void hide(); void hide();
void new_file_entry(); void new_file_dialog();
void new_folder_dialog();
void new_cpp_project_dialog(); void new_cpp_project_dialog();
void open_folder_dialog(); void open_folder_dialog();
void open_file_dialog(); void open_file_dialog();

Loading…
Cancel
Save