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
5674016941
  1. 11
      src/entrybox.cc
  2. 5
      src/files.h
  3. 1
      src/menu.cc
  4. 99
      src/notebook.cc
  5. 8
      src/notebook.h
  6. 149
      src/source.cc
  7. 23
      src/source.h
  8. 33
      src/terminal.cc
  9. 20
      src/terminal.h
  10. 60
      src/tooltips.cc
  11. 6
      src/tooltips.h
  12. 72
      src/window.cc
  13. 4
      src/window.h

11
src/entrybox.cc

@ -37,6 +37,7 @@ EntryBox::Label::Label(std::function<void(int state, const std::string& message)
EntryBox::EntryBox() : Gtk::Box(Gtk::ORIENTATION_VERTICAL), upper_box(Gtk::ORIENTATION_HORIZONTAL), lower_box(Gtk::ORIENTATION_HORIZONTAL) { EntryBox::EntryBox() : Gtk::Box(Gtk::ORIENTATION_VERTICAL), upper_box(Gtk::ORIENTATION_HORIZONTAL), lower_box(Gtk::ORIENTATION_HORIZONTAL) {
pack_start(upper_box, Gtk::PACK_SHRINK); pack_start(upper_box, Gtk::PACK_SHRINK);
pack_start(lower_box, Gtk::PACK_SHRINK); pack_start(lower_box, Gtk::PACK_SHRINK);
this->set_focus_chain({&lower_box});
} }
void EntryBox::clear() { void EntryBox::clear() {
@ -50,16 +51,16 @@ void EntryBox::clear() {
void EntryBox::show() { void EntryBox::show() {
std::vector<Gtk::Widget*> focus_chain; std::vector<Gtk::Widget*> focus_chain;
for(auto& entry: entries) { for(auto& entry: entries) {
upper_box.pack_start(entry, Gtk::PACK_SHRINK); lower_box.pack_start(entry, Gtk::PACK_SHRINK);
focus_chain.emplace_back(&entry); focus_chain.emplace_back(&entry);
} }
for(auto& button: buttons) for(auto& button: buttons)
upper_box.pack_start(button, Gtk::PACK_SHRINK); lower_box.pack_start(button, Gtk::PACK_SHRINK);
for(auto& toggle_button: toggle_buttons) for(auto& toggle_button: toggle_buttons)
upper_box.pack_start(toggle_button, Gtk::PACK_SHRINK); lower_box.pack_start(toggle_button, Gtk::PACK_SHRINK);
for(auto& label: labels) for(auto& label: labels)
lower_box.pack_start(label, Gtk::PACK_SHRINK); upper_box.pack_start(label, Gtk::PACK_SHRINK);
upper_box.set_focus_chain(focus_chain); lower_box.set_focus_chain(focus_chain);
show_all(); show_all();
if(entries.size()>0) { if(entries.size()>0) {
entries.begin()->grab_focus(); entries.begin()->grab_focus();

5
src/files.h

@ -47,6 +47,8 @@ const std::string configjson =
" \"edit_undo\": \"<primary>z\",\n" " \"edit_undo\": \"<primary>z\",\n"
" \"edit_redo\": \"<primary><shift>z\",\n" " \"edit_redo\": \"<primary><shift>z\",\n"
" \"edit_find\": \"<primary>f\",\n" " \"edit_find\": \"<primary>f\",\n"
" \"source_goto_line\": \"<primary>g\",\n"
" \"source_center_cursor\": \"<primary>l\",\n"
" \"source_goto_declaration\": \"<primary>d\",\n" " \"source_goto_declaration\": \"<primary>d\",\n"
" \"source_goto_method\": \"<primary>m\",\n" " \"source_goto_method\": \"<primary>m\",\n"
" \"source_rename\": \"<primary>r\",\n" " \"source_rename\": \"<primary>r\",\n"
@ -112,6 +114,9 @@ const std::string menuxml =
" <menuitem action=\"EditRedo\"/>\n" " <menuitem action=\"EditRedo\"/>\n"
" </menu>\n" " </menu>\n"
" <menu action=\"SourceMenu\">\n" " <menu action=\"SourceMenu\">\n"
" <menuitem action=\"SourceGotoLine\"/>\n"
" <menuitem action=\"SourceCenterCursor\"/>\n"
" <separator/>\n"
" <menuitem action=\"SourceGotoDeclaration\"/>\n" " <menuitem action=\"SourceGotoDeclaration\"/>\n"
" <menuitem action=\"SourceGotoMethod\"/>\n" " <menuitem action=\"SourceGotoMethod\"/>\n"
" <menuitem action=\"SourceRename\"/>\n" " <menuitem action=\"SourceRename\"/>\n"

1
src/menu.cc

@ -33,4 +33,3 @@ void Menu::build() {
} }
ui_manager->insert_action_group(action_group); ui_manager->insert_action_group(action_group);
} }

99
src/notebook.cc

@ -3,12 +3,16 @@
#include "sourcefile.h" #include "sourcefile.h"
#include "singletons.h" #include "singletons.h"
#include <fstream> #include <fstream>
#include <regex>
#include <iostream> //TODO: remove
using namespace std; //TODO: remove
namespace sigc { namespace sigc {
SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE
} }
Notebook::Notebook() : Gtk::Notebook() { Notebook::Notebook(Directories &directories) : Gtk::Notebook(), directories(directories) {
Gsv::init(); Gsv::init();
} }
@ -19,7 +23,7 @@ int Notebook::size() {
Source::View* Notebook::get_view(int page) { Source::View* Notebook::get_view(int page) {
if(page>=size()) if(page>=size())
return nullptr; return nullptr;
return source_views.at(page).get(); return source_views.at(page);
} }
Source::View* Notebook::get_current_view() { Source::View* Notebook::get_current_view() {
@ -47,15 +51,29 @@ void Notebook::open(std::string path) {
} }
can_read.close(); can_read.close();
auto tmp_project_path=project_path;
if(tmp_project_path=="") {
tmp_project_path=boost::filesystem::path(path).parent_path().string();
}
auto language=Source::guess_language(path); auto language=Source::guess_language(path);
if(language && (language->get_id()=="chdr" || language->get_id()=="c" || language->get_id()=="cpp" || language->get_id()=="objc")) if(language && (language->get_id()=="chdr" || language->get_id()=="c" || language->get_id()=="cpp" || language->get_id()=="objc")) {
source_views.emplace_back(new Source::ClangView(path, tmp_project_path)); auto view_project_path=project_path;
if(view_project_path=="") {
view_project_path=boost::filesystem::path(path).parent_path().string();
auto found_project_path=find_project_path(view_project_path);
if(found_project_path!="") {
view_project_path=found_project_path;
Singleton::terminal()->print("Project path for "+path+" set to "+view_project_path+"\n");
}
else else
source_views.emplace_back(new Source::GenericView(path, tmp_project_path, language)); Singleton::terminal()->print("Error: could not find project path for "+path+"\n");
}
if(boost::filesystem::exists(view_project_path+"/CMakeLists.txt") && !boost::filesystem::exists(view_project_path+"/compile_commands.json"))
make_compile_commands(view_project_path);
source_views.emplace_back(new Source::ClangView(path, view_project_path));
}
else {
auto view_project_path=project_path;
if(view_project_path=="")
view_project_path=boost::filesystem::path(path).parent_path().string();
source_views.emplace_back(new Source::GenericView(path, view_project_path, language));
}
scrolled_windows.emplace_back(new Gtk::ScrolledWindow()); scrolled_windows.emplace_back(new Gtk::ScrolledWindow());
hboxes.emplace_back(new Gtk::HBox()); hboxes.emplace_back(new Gtk::HBox());
@ -94,6 +112,32 @@ void Notebook::open(std::string path) {
}; };
} }
std::string Notebook::find_project_path(const std::string &path) {
const auto find_cmake_project=[this](const boost::filesystem::path &path) {
auto cmake_path=path;
cmake_path+="/CMakeLists.txt";
for(auto &line: juci::filesystem::read_lines(cmake_path)) {
const std::regex cmake_project("^ *project *\\(.*$");
std::smatch sm;
if(std::regex_match(line, sm, cmake_project)) {
return true;
}
}
return false;
};
auto boost_path=boost::filesystem::path(path);
if(find_cmake_project(boost_path))
return boost_path.string();
do {
boost_path=boost_path.parent_path();
if(find_cmake_project(boost_path))
return boost_path.string();
} while(boost_path!=boost_path.root_directory());
return "";
}
bool Notebook::save(int page) { bool Notebook::save(int page) {
if(page>=size()) if(page>=size())
return false; return false;
@ -102,10 +146,38 @@ bool Notebook::save(int page) {
if(juci::filesystem::write(view->file_path, view->get_buffer())) { if(juci::filesystem::write(view->file_path, view->get_buffer())) {
view->get_buffer()->set_modified(false); view->get_buffer()->set_modified(false);
Singleton::terminal()->print("File saved to: " +view->file_path+"\n"); Singleton::terminal()->print("File saved to: " +view->file_path+"\n");
return true;
//If CMakeLists.txt have been modified:
if(boost::filesystem::path(view->file_path).filename().string()=="CMakeLists.txt") {
if(project_path!="" && make_compile_commands(project_path)) {
for(auto source_view: source_views) {
if(auto source_clang_view=dynamic_cast<Source::ClangView*>(source_view)) {
if(project_path==source_view->project_path) {
if(source_clang_view->restart_parse())
Singleton::terminal()->print("Reparsing "+source_clang_view->file_path+"\n");
else
Singleton::terminal()->print("Already reparsing "+source_clang_view->file_path+". Please reopen the file manually.\n");
}
}
} }
} }
}
return true;
}
Singleton::terminal()->print("Error: could not save file " +view->file_path+"\n"); Singleton::terminal()->print("Error: could not save file " +view->file_path+"\n");
}
return false;
}
bool Notebook::make_compile_commands(const std::string &path) {
Singleton::terminal()->print("Creating "+boost::filesystem::path(path+"/compile_commands.json").string()+"\n");
//TODO: Windows...
if(Singleton::terminal()->execute(path, "cmake . -DCMAKE_EXPORT_COMPILE_COMMANDS=ON 2>&1")) {
if(project_path!="")
directories.open_folder(project_path);
return true;
}
return false; return false;
} }
@ -125,9 +197,16 @@ bool Notebook::close_current_page() {
} }
int page = get_current_page(); int page = get_current_page();
remove_page(page); remove_page(page);
if(get_current_page()==-1)
Singleton::status()->set_text("");
auto source_view=source_views.at(page);
source_views.erase(source_views.begin()+ page); source_views.erase(source_views.begin()+ page);
scrolled_windows.erase(scrolled_windows.begin()+page); scrolled_windows.erase(scrolled_windows.begin()+page);
hboxes.erase(hboxes.begin()+page); hboxes.erase(hboxes.begin()+page);
if(auto source_clang_view=dynamic_cast<Source::ClangView*>(source_view))
source_clang_view->async_delete();
else
delete source_view;
} }
return true; return true;
} }

8
src/notebook.h

@ -8,10 +8,11 @@
#include <type_traits> #include <type_traits>
#include <map> #include <map>
#include <sigc++/sigc++.h> #include <sigc++/sigc++.h>
#include "directories.h"
class Notebook : public Gtk::Notebook { class Notebook : public Gtk::Notebook {
public: public:
Notebook(); Notebook(Directories &directories);
Source::View* get_view(int page); Source::View* get_view(int page);
int size(); int size();
Source::View* get_current_view(); Source::View* get_current_view();
@ -22,8 +23,11 @@ public:
std::string project_path; std::string project_path;
private: private:
std::string find_project_path(const std::string &path);
bool make_compile_commands(const std::string &path);
bool save_modified_dialog(); bool save_modified_dialog();
std::vector<std::unique_ptr<Source::View> > source_views; Directories &directories;
std::vector<Source::View*> source_views; //Is NOT freed in destructor, this is intended for quick program exit.
std::vector<std::unique_ptr<Gtk::ScrolledWindow> > scrolled_windows; std::vector<std::unique_ptr<Gtk::ScrolledWindow> > scrolled_windows;
std::vector<std::unique_ptr<Gtk::HBox> > hboxes; std::vector<std::unique_ptr<Gtk::HBox> > hboxes;
}; };

149
src/source.cc

@ -278,8 +278,7 @@ Source::GenericView::GenericView(const std::string& file_path, const std::string
clang::Index Source::ClangViewParse::clang_index(0, 0); clang::Index Source::ClangViewParse::clang_index(0, 0);
Source::ClangViewParse::ClangViewParse(const std::string& file_path, const std::string& project_path): Source::ClangViewParse::ClangViewParse(const std::string& file_path, const std::string& project_path):
Source::View(file_path, project_path), Source::View(file_path, project_path) {
parse_thread_go(true), parse_thread_mapped(false), parse_thread_stop(false) {
override_font(Pango::FontDescription(Singleton::Config::source()->font)); override_font(Pango::FontDescription(Singleton::Config::source()->font));
override_background_color(Gdk::RGBA(Singleton::Config::source()->background)); override_background_color(Gdk::RGBA(Singleton::Config::source()->background));
override_background_color(Gdk::RGBA(Singleton::Config::source()->background_selected), Gtk::StateFlags::STATE_FLAG_SELECTED); override_background_color(Gdk::RGBA(Singleton::Config::source()->background_selected), Gtk::StateFlags::STATE_FLAG_SELECTED);
@ -308,27 +307,7 @@ parse_thread_go(true), parse_thread_mapped(false), parse_thread_stop(false) {
} }
//TODO: clear tag_class and param_spec? //TODO: clear tag_class and param_spec?
int start_offset = get_source_buffer()->begin().get_offset(); parsing_in_progress=Singleton::terminal()->print_in_progress("Parsing "+file_path);
int end_offset = get_source_buffer()->end().get_offset();
auto buffer_map=get_buffer_map();
//Remove includes for first parse for initial syntax highlighting
auto& str=buffer_map[file_path];
std::size_t pos=0;
while((pos=str.find("#include", pos))!=std::string::npos) {
auto start_pos=pos;
pos=str.find('\n', pos+8);
if(pos==std::string::npos)
break;
if(start_pos==0 || str[start_pos-1]=='\n') {
str.replace(start_pos, pos-start_pos, pos-start_pos, ' ');
}
pos++;
}
init_syntax_highlighting(buffer_map,
start_offset,
end_offset);
update_syntax();
//GTK-calls must happen in main thread, so the parse_thread //GTK-calls must happen in main thread, so the parse_thread
//sends signals to the main thread that it is to call the following functions: //sends signals to the main thread that it is to call the following functions:
parse_start.connect([this]{ parse_start.connect([this]{
@ -339,8 +318,6 @@ parse_thread_go(true), parse_thread_mapped(false), parse_thread_stop(false) {
} }
parse_thread_go=true; parse_thread_go=true;
}); });
parsing_in_progress=Singleton::terminal()->print_in_progress("Parsing "+file_path);
parse_done.connect([this](){ parse_done.connect([this](){
if(parse_thread_mapped) { if(parse_thread_mapped) {
if(parsing_mutex.try_lock()) { if(parsing_mutex.try_lock()) {
@ -359,8 +336,51 @@ parse_thread_go(true), parse_thread_mapped(false), parse_thread_stop(false) {
parse_thread_go=true; parse_thread_go=true;
} }
}); });
init_parse();
get_buffer()->signal_changed().connect([this]() {
start_reparse();
type_tooltips.hide();
diagnostic_tooltips.hide();
});
get_buffer()->signal_mark_set().connect(sigc::mem_fun(*this, &Source::ClangViewParse::on_mark_set), false);
}
void Source::ClangViewParse::init_parse() {
type_tooltips.hide();
diagnostic_tooltips.hide();
get_buffer()->remove_all_tags(get_buffer()->begin(), get_buffer()->end());
clang_readable=false;
parse_thread_go=true;
parse_thread_mapped=false;
parse_thread_stop=false;
int start_offset = get_source_buffer()->begin().get_offset();
int end_offset = get_source_buffer()->end().get_offset();
auto buffer_map=get_buffer_map();
//Remove includes for first parse for initial syntax highlighting
auto& str=buffer_map[file_path];
std::size_t pos=0;
while((pos=str.find("#include", pos))!=std::string::npos) {
auto start_pos=pos;
pos=str.find('\n', pos+8);
if(pos==std::string::npos)
break;
if(start_pos==0 || str[start_pos-1]=='\n') {
str.replace(start_pos, pos-start_pos, pos-start_pos, ' ');
}
pos++;
}
init_syntax_highlighting(buffer_map,
start_offset,
end_offset);
update_syntax();
set_status("parsing..."); set_status("parsing...");
if(parse_thread.joinable())
parse_thread.join();
parse_thread=std::thread([this]() { parse_thread=std::thread([this]() {
while(true) { while(true) {
while(!parse_thread_go && !parse_thread_stop) while(!parse_thread_go && !parse_thread_stop)
@ -380,24 +400,6 @@ parse_thread_go(true), parse_thread_mapped(false), parse_thread_stop(false) {
} }
} }
}); });
get_buffer()->signal_changed().connect([this]() {
start_reparse();
type_tooltips.hide();
diagnostic_tooltips.hide();
});
get_buffer()->signal_mark_set().connect(sigc::mem_fun(*this, &Source::ClangViewParse::on_mark_set), false);
}
Source::ClangViewParse::~ClangViewParse() {
//TODO: Is it possible to stop the clang-process in progress?
parsing_in_progress->cancel("canceled");
parse_thread_stop=true;
if(parse_thread.joinable())
parse_thread.join();
parsing_mutex.lock(); //Be sure not to destroy while still parsing with libclang
parsing_mutex.unlock();
} }
void Source::ClangViewParse:: void Source::ClangViewParse::
@ -506,14 +508,14 @@ void Source::ClangViewParse::update_diagnostics() {
auto spelling=diagnostic.spelling; auto spelling=diagnostic.spelling;
auto severity_spelling=diagnostic.severity_spelling; auto severity_spelling=diagnostic.severity_spelling;
auto get_tooltip_buffer=[this, spelling, severity_spelling, diagnostic_tag_name]() { auto create_tooltip_buffer=[this, spelling, severity_spelling, diagnostic_tag_name]() {
auto tooltip_buffer=Gtk::TextBuffer::create(get_buffer()->get_tag_table()); auto tooltip_buffer=Gtk::TextBuffer::create(get_buffer()->get_tag_table());
tooltip_buffer->insert_with_tag(tooltip_buffer->get_insert()->get_iter(), severity_spelling, diagnostic_tag_name); tooltip_buffer->insert_with_tag(tooltip_buffer->get_insert()->get_iter(), severity_spelling, diagnostic_tag_name);
tooltip_buffer->insert_at_cursor(":\n"+spelling); tooltip_buffer->insert_at_cursor(":\n"+spelling);
//TODO: Insert newlines to clang_tu->diagnostics[c].spelling (use 80 chars, then newline?) //TODO: Insert newlines to clang_tu->diagnostics[c].spelling (use 80 chars, then newline?)
return tooltip_buffer; return tooltip_buffer;
}; };
diagnostic_tooltips.emplace_back(get_tooltip_buffer, *this, get_buffer()->create_mark(start), get_buffer()->create_mark(end)); diagnostic_tooltips.emplace_back(create_tooltip_buffer, *this, get_buffer()->create_mark(start), get_buffer()->create_mark(end));
get_buffer()->apply_tag_by_name(diagnostic_tag_name+"_underline", start, end); get_buffer()->apply_tag_by_name(diagnostic_tag_name+"_underline", start, end);
} }
@ -526,7 +528,7 @@ void Source::ClangViewParse::update_types() {
if(token.get_kind()==clang::Token_Identifier && token.has_type()) { if(token.get_kind()==clang::Token_Identifier && token.has_type()) {
auto start=get_buffer()->get_iter_at_offset(token.offsets.first); auto start=get_buffer()->get_iter_at_offset(token.offsets.first);
auto end=get_buffer()->get_iter_at_offset(token.offsets.second); auto end=get_buffer()->get_iter_at_offset(token.offsets.second);
auto get_tooltip_buffer=[this, &token]() { auto create_tooltip_buffer=[this, &token]() {
auto tooltip_buffer=Gtk::TextBuffer::create(get_buffer()->get_tag_table()); auto tooltip_buffer=Gtk::TextBuffer::create(get_buffer()->get_tag_table());
tooltip_buffer->insert_at_cursor("Type: "+token.get_type()); tooltip_buffer->insert_at_cursor("Type: "+token.get_type());
auto brief_comment=token.get_brief_comments(); auto brief_comment=token.get_brief_comments();
@ -535,14 +537,14 @@ void Source::ClangViewParse::update_types() {
return tooltip_buffer; return tooltip_buffer;
}; };
type_tooltips.emplace_back(get_tooltip_buffer, *this, get_buffer()->create_mark(start), get_buffer()->create_mark(end)); type_tooltips.emplace_back(create_tooltip_buffer, *this, get_buffer()->create_mark(start), get_buffer()->create_mark(end));
} }
} }
} }
bool Source::ClangViewParse::on_motion_notify_event(GdkEventMotion* event) { bool Source::ClangViewParse::on_motion_notify_event(GdkEventMotion* event) {
delayed_tooltips_connection.disconnect(); delayed_tooltips_connection.disconnect();
if(clang_readable) { if(clang_readable && event->state==0) {
Gdk::Rectangle rectangle(event->x, event->y, 1, 1); Gdk::Rectangle rectangle(event->x, event->y, 1, 1);
Tooltips::init(); Tooltips::init();
type_tooltips.show(rectangle); type_tooltips.show(rectangle);
@ -872,14 +874,14 @@ void Source::ClangViewAutocomplete::autocomplete() {
} }
buffer+="\n"; buffer+="\n";
set_status("autocomplete..."); set_status("autocomplete...");
std::thread autocomplete_thread([this, ac_data, line_nr, column_nr, buffer_map](){ if(autocomplete_thread.joinable())
autocomplete_thread.join();
autocomplete_thread=std::thread([this, ac_data, line_nr, column_nr, buffer_map](){
parsing_mutex.lock(); parsing_mutex.lock();
*ac_data=move(get_autocomplete_suggestions(line_nr, column_nr, *buffer_map)); *ac_data=move(get_autocomplete_suggestions(line_nr, column_nr, *buffer_map));
autocomplete_done(); autocomplete_done();
parsing_mutex.unlock(); parsing_mutex.unlock();
}); });
autocomplete_thread.detach();
} }
} }
@ -1051,3 +1053,48 @@ Source::ClangViewAutocomplete(file_path, project_path) {
} }
}; };
} }
Source::ClangView::ClangView(const std::string& file_path, const std::string& project_path): ClangViewRefactor(file_path, project_path) {
do_delete_object.connect([this](){
if(delete_thread.joinable())
delete_thread.join();
delete this;
});
do_restart_parse.connect([this](){
init_parse();
restart_parse_running=false;
});
}
void Source::ClangView::async_delete() {
parsing_in_progress->cancel("canceled, freeing resources in the background");
parse_thread_stop=true;
delete_thread=std::thread([this](){
//TODO: Is it possible to stop the clang-process in progress?
if(restart_parse_thread.joinable())
restart_parse_thread.join();
if(parse_thread.joinable())
parse_thread.join();
if(autocomplete_thread.joinable())
autocomplete_thread.join();
do_delete_object();
});
}
bool Source::ClangView::restart_parse() {
if(!restart_parse_running) {
restart_parse_running=true;
parse_thread_stop=true;
if(restart_parse_thread.joinable())
restart_parse_thread.join();
restart_parse_thread=std::thread([this](){
if(parse_thread.joinable())
parse_thread.join();
if(autocomplete_thread.joinable())
autocomplete_thread.join();
do_restart_parse();
});
return true;
}
return false;
}

23
src/source.h

@ -90,17 +90,21 @@ namespace Source {
class ClangViewParse : public View { class ClangViewParse : public View {
public: public:
ClangViewParse(const std::string& file_path, const std::string& project_path); ClangViewParse(const std::string& file_path, const std::string& project_path);
~ClangViewParse();
protected: protected:
void init_parse();
void start_reparse(); void start_reparse();
bool on_key_press_event(GdkEventKey* key); bool on_key_press_event(GdkEventKey* key);
bool on_focus_out_event(GdkEventFocus* event); bool on_focus_out_event(GdkEventFocus* event);
std::unique_ptr<clang::TranslationUnit> clang_tu; std::unique_ptr<clang::TranslationUnit> clang_tu;
std::mutex parsing_mutex; std::mutex parsing_mutex;
std::unique_ptr<clang::Tokens> clang_tokens; std::unique_ptr<clang::Tokens> clang_tokens;
bool clang_readable=false; bool clang_readable;
sigc::connection delayed_reparse_connection; sigc::connection delayed_reparse_connection;
sigc::connection delayed_tooltips_connection; sigc::connection delayed_tooltips_connection;
std::shared_ptr<Terminal::InProgress> parsing_in_progress;
std::thread parse_thread;
std::atomic<bool> parse_thread_stop;
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
@ -122,15 +126,12 @@ namespace Source {
static clang::Index clang_index; static clang::Index clang_index;
std::vector<std::string> get_compilation_commands(); std::vector<std::string> get_compilation_commands();
std::shared_ptr<Terminal::InProgress> parsing_in_progress;
Glib::Dispatcher parse_done; Glib::Dispatcher parse_done;
Glib::Dispatcher parse_start; Glib::Dispatcher parse_start;
std::thread parse_thread;
std::map<std::string, std::string> parse_thread_buffer_map; std::map<std::string, std::string> parse_thread_buffer_map;
std::mutex parse_thread_buffer_map_mutex; std::mutex parse_thread_buffer_map_mutex;
std::atomic<bool> parse_thread_go; std::atomic<bool> parse_thread_go;
std::atomic<bool> parse_thread_mapped; std::atomic<bool> parse_thread_mapped;
std::atomic<bool> parse_thread_stop;
}; };
class ClangViewAutocomplete : public ClangViewParse { class ClangViewAutocomplete : public ClangViewParse {
@ -139,6 +140,7 @@ namespace Source {
protected: protected:
bool on_key_press_event(GdkEventKey* key); bool on_key_press_event(GdkEventKey* key);
bool on_focus_out_event(GdkEventFocus* event); bool on_focus_out_event(GdkEventFocus* event);
std::thread autocomplete_thread;
private: private:
void start_autocomplete(); void start_autocomplete();
void autocomplete(); void autocomplete();
@ -166,8 +168,15 @@ namespace Source {
class ClangView : public ClangViewRefactor { class ClangView : public ClangViewRefactor {
public: public:
ClangView(const std::string& file_path, const std::string& project_path): ClangView(const std::string& file_path, const std::string& project_path);
ClangViewRefactor(file_path, project_path) {} void async_delete();
bool restart_parse();
private:
Glib::Dispatcher do_delete_object;
Glib::Dispatcher do_restart_parse;
std::thread delete_thread;
std::thread restart_parse_thread;
bool restart_parse_running=false;
}; };
}; // class Source }; // class Source
#endif // JUCI_SOURCE_H_ #endif // JUCI_SOURCE_H_

33
src/terminal.cc

@ -56,6 +56,39 @@ Terminal::Terminal() {
}); });
} }
bool Terminal::execute(const std::string &path, const std::string &command) {
boost::filesystem::path boost_path;
if(path=="")
boost_path=boost::filesystem::current_path();
else
boost_path=boost::filesystem::path(path);
//TODO: Windows...
auto cd_path_and_command="cd "+boost_path.string()+" 2>&1 && "+command;
FILE* p = NULL;
p = popen(cd_path_and_command.c_str(), "r");
if (p == NULL) {
print("Error: Failed to run command" + command + "\n");
return false;
}
else {
char buffer[1028];
while (fgets(buffer, 1028, p) != NULL) {
print(buffer);
}
int exit_code=pclose(p);
if(exit_code==0)
return true;
else
return false;
}
}
void Terminal::async_execute(const std::string &path, const std::string &command) {
}
void Terminal::set_change_folder_command(boost::filesystem::path CMake_path) { void Terminal::set_change_folder_command(boost::filesystem::path CMake_path) {
INFO("Terminal: set_change_folder_command"); INFO("Terminal: set_change_folder_command");
path = CMake_path.string(); path = CMake_path.string();

20
src/terminal.h

@ -31,23 +31,25 @@ public:
}; };
Terminal(); Terminal();
void set_change_folder_command(boost::filesystem::path CMake_path); bool execute(const std::string &path, const std::string &command);
void run(std::string executable); void async_execute(const std::string &path, const std::string &command);
void compile(); void set_change_folder_command(boost::filesystem::path CMake_path); //TODO: remove
void run(std::string executable); //TODO: remove
void compile(); //TODO: remove
int print(std::string message); int print(std::string message);
void print(int line_nr, std::string message); void print(int line_nr, std::string message);
std::shared_ptr<InProgress> print_in_progress(std::string start_msg); std::shared_ptr<InProgress> print_in_progress(std::string start_msg);
private: private:
void execute_command(std::string command, std::string mode); void execute_command(std::string command, std::string mode); //TODO: remove
Gtk::TextView text_view; Gtk::TextView text_view;
Gtk::ScrolledWindow scrolled_window; Gtk::ScrolledWindow scrolled_window;
std::string change_folder_command; std::string change_folder_command; //TODO: remove
std::string path; std::string path; //TODO: remove
const std::string cmake_sucsess = "Build files have been written to:"; const std::string cmake_sucsess = "Build files have been written to:"; //TODO: remove
const std::string make_built = "Built target"; const std::string make_built = "Built target"; //TODO: remove
const std::string make_executable = "Linking CXX executable"; const std::string make_executable = "Linking CXX executable"; //TODO: remove
}; };
#endif // JUCI_TERMINAL_H_ #endif // JUCI_TERMINAL_H_

60
src/tooltips.cc

@ -1,11 +1,15 @@
#include "tooltips.h" #include "tooltips.h"
#include "singletons.h" #include "singletons.h"
namespace sigc {
SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE
}
Gdk::Rectangle Tooltips::drawn_tooltips_rectangle=Gdk::Rectangle(); Gdk::Rectangle Tooltips::drawn_tooltips_rectangle=Gdk::Rectangle();
Tooltip::Tooltip(std::function<Glib::RefPtr<Gtk::TextBuffer>()> get_buffer, Gtk::TextView& text_view, Tooltip::Tooltip(std::function<Glib::RefPtr<Gtk::TextBuffer>()> create_tooltip_buffer, Gtk::TextView& text_view,
Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark, Glib::RefPtr<Gtk::TextBuffer::Mark> end_mark): Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark, Glib::RefPtr<Gtk::TextBuffer::Mark> end_mark):
get_buffer(get_buffer), text_view(text_view), create_tooltip_buffer(create_tooltip_buffer), text_view(text_view),
start_mark(start_mark), end_mark(end_mark) {} start_mark(start_mark), end_mark(end_mark) {}
Tooltip::~Tooltip() { Tooltip::~Tooltip() {
@ -38,13 +42,17 @@ void Tooltip::adjust(bool disregard_drawn) {
window=std::unique_ptr<Gtk::Window>(new Gtk::Window(Gtk::WindowType::WINDOW_POPUP)); window=std::unique_ptr<Gtk::Window>(new Gtk::Window(Gtk::WindowType::WINDOW_POPUP));
window->set_events(Gdk::POINTER_MOTION_MASK); window->set_events(Gdk::POINTER_MOTION_MASK);
window->signal_motion_notify_event().connect(sigc::mem_fun(*this, &Tooltip::tooltip_on_motion_notify_event), false); window->signal_motion_notify_event().connect([this](GdkEventMotion* event){
window->hide();
return false;
});
window->property_decorated()=false; window->property_decorated()=false;
window->set_accept_focus(false); window->set_accept_focus(false);
window->set_skip_taskbar_hint(true); window->set_skip_taskbar_hint(true);
window->set_default_size(0, 0); window->set_default_size(0, 0);
tooltip_widget=std::unique_ptr<Gtk::TextView>(new Gtk::TextView(this->get_buffer())); tooltip_widget=std::unique_ptr<Gtk::TextView>(new Gtk::TextView(create_tooltip_buffer()));
wrap_lines(tooltip_widget->get_buffer());
tooltip_widget->set_editable(false); tooltip_widget->set_editable(false);
tooltip_widget->override_background_color(Gdk::RGBA(Singleton::Config::source()->background_tooltips)); tooltip_widget->override_background_color(Gdk::RGBA(Singleton::Config::source()->background_tooltips));
window->add(*tooltip_widget); window->add(*tooltip_widget);
@ -76,9 +84,47 @@ void Tooltip::adjust(bool disregard_drawn) {
window->move(rectangle.get_x(), rectangle.get_y()); window->move(rectangle.get_x(), rectangle.get_y());
} }
bool Tooltip::tooltip_on_motion_notify_event(GdkEventMotion* event) { void Tooltip::wrap_lines(Glib::RefPtr<Gtk::TextBuffer> text_buffer) {
window->hide(); INFO("Tooltip::wrap_lines");
return false; auto iter=text_buffer->begin();
while(iter) {
auto last_space=text_buffer->end();
bool end=false;
for(unsigned c=0;c<=80;c++) {
if(!iter) {
end=true;
break;
}
if(*iter==' ')
last_space=iter;
if(*iter=='\n') {
end=true;
iter++;
break;
}
iter++;
}
if(!end) {
while(!last_space && iter) { //If no space (word longer than 80)
iter++;
if(iter && *iter==' ')
last_space=iter;
}
if(iter && last_space) {
auto mark=text_buffer->create_mark(last_space);
auto iter_mark=text_buffer->create_mark(iter);
auto last_space_p=last_space++;
text_buffer->erase(last_space, last_space_p);
text_buffer->insert(mark->get_iter(), "\n");
iter=iter_mark->get_iter();
text_buffer->delete_mark(mark);
text_buffer->delete_mark(iter_mark);
}
}
}
} }
void Tooltips::show(const Gdk::Rectangle& rectangle, bool disregard_drawn) { void Tooltips::show(const Gdk::Rectangle& rectangle, bool disregard_drawn) {

6
src/tooltips.h

@ -6,7 +6,7 @@
class Tooltip { class Tooltip {
public: public:
Tooltip(std::function<Glib::RefPtr<Gtk::TextBuffer>()> get_buffer, Gtk::TextView& text_view, Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark, Glib::RefPtr<Gtk::TextBuffer::Mark> end_mark); Tooltip(std::function<Glib::RefPtr<Gtk::TextBuffer>()> create_tooltip_buffer, Gtk::TextView& text_view, Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark, Glib::RefPtr<Gtk::TextBuffer::Mark> end_mark);
~Tooltip(); ~Tooltip();
void update(); void update();
@ -15,9 +15,9 @@ public:
Gdk::Rectangle activation_rectangle; Gdk::Rectangle activation_rectangle;
std::unique_ptr<Gtk::Window> window; std::unique_ptr<Gtk::Window> window;
private: private:
bool tooltip_on_motion_notify_event(GdkEventMotion* event); void wrap_lines(Glib::RefPtr<Gtk::TextBuffer> text_buffer);
std::function<Glib::RefPtr<Gtk::TextBuffer>()> get_buffer; std::function<Glib::RefPtr<Gtk::TextBuffer>()> create_tooltip_buffer;
std::unique_ptr<Gtk::TextView> tooltip_widget; std::unique_ptr<Gtk::TextView> tooltip_widget;
Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark; Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark;
Glib::RefPtr<Gtk::TextBuffer::Mark> end_mark; Glib::RefPtr<Gtk::TextBuffer::Mark> end_mark;

72
src/window.cc

@ -5,11 +5,14 @@
#include "config.h" #include "config.h"
#include "api.h" #include "api.h"
#include <iostream> //TODO: remove
using namespace std; //TODO: remove
namespace sigc { namespace sigc {
SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE
} }
Window::Window() : box(Gtk::ORIENTATION_VERTICAL) { Window::Window() : box(Gtk::ORIENTATION_VERTICAL), notebook(directories) {
INFO("Create Window"); INFO("Create Window");
set_title("juCi++"); set_title("juCi++");
set_default_size(600, 400); set_default_size(600, 400);
@ -21,10 +24,10 @@ Window::Window() : box(Gtk::ORIENTATION_VERTICAL) {
create_menu(); create_menu();
box.pack_start(menu.get_widget(), Gtk::PACK_SHRINK); box.pack_start(menu.get_widget(), Gtk::PACK_SHRINK);
box.pack_start(entry_box, Gtk::PACK_SHRINK); directory_and_notebook_panes.pack1(directories, Gtk::SHRINK);
notebook_vbox.pack_start(notebook);
directory_and_notebook_panes.pack1(directories, true, true); notebook_vbox.pack_end(entry_box, Gtk::PACK_SHRINK);
directory_and_notebook_panes.pack2(notebook); directory_and_notebook_panes.pack2(notebook_vbox, Gtk::SHRINK);
directory_and_notebook_panes.set_position(120); directory_and_notebook_panes.set_position(120);
vpaned.set_position(300); vpaned.set_position(300);
vpaned.pack1(directory_and_notebook_panes, true, false); vpaned.pack1(directory_and_notebook_panes, true, false);
@ -42,12 +45,16 @@ Window::Window() : box(Gtk::ORIENTATION_VERTICAL) {
}; };
entry_box.signal_show().connect([this](){ entry_box.signal_show().connect([this](){
std::vector<Gtk::Widget*> focus_chain; box.set_focus_chain({&vpaned});
focus_chain.emplace_back(&entry_box); vpaned.set_focus_chain({&directory_and_notebook_panes});
box.set_focus_chain(focus_chain); directory_and_notebook_panes.set_focus_chain({&notebook_vbox});
notebook_vbox.set_focus_chain({&entry_box});
}); });
entry_box.signal_hide().connect([this](){ entry_box.signal_hide().connect([this](){
box.unset_focus_chain(); box.unset_focus_chain();
vpaned.unset_focus_chain();
directory_and_notebook_panes.unset_focus_chain();
notebook_vbox.unset_focus_chain();
}); });
entry_box.signal_hide().connect([this]() { entry_box.signal_hide().connect([this]() {
if(notebook.get_current_page()!=-1) { if(notebook.get_current_page()!=-1) {
@ -78,6 +85,9 @@ Window::Window() : box(Gtk::ORIENTATION_VERTICAL) {
Singleton::status()->set_text(notebook.get_current_view()->status); Singleton::status()->set_text(notebook.get_current_view()->status);
} }
}); });
notebook.signal_page_removed().connect([this](Gtk::Widget* page, guint page_num) {
entry_box.hide();
});
INFO("Window created"); INFO("Window created");
} // Window constructor } // Window constructor
@ -148,6 +158,16 @@ 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]() {
goto_line_entry();
});
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) {
while(gtk_events_pending())
gtk_main_iteration();
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) {
@ -446,14 +466,6 @@ 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("Find", [this](){
if(notebook.get_current_page()!=-1)
notebook.get_current_view()->search_forward();
});
entry_box.buttons.emplace_back("Replace", [this, replace_entry_it](){
if(notebook.get_current_page()!=-1)
notebook.get_current_view()->replace_forward(replace_entry_it->get_text());
});
entry_box.buttons.emplace_back("Replace all", [this, replace_entry_it](){ entry_box.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());
@ -483,6 +495,34 @@ void Window::search_and_replace_entry() {
entry_box.show(); entry_box.show();
} }
void Window::goto_line_entry() {
entry_box.clear();
if(notebook.get_current_page()!=-1) {
entry_box.entries.emplace_back("", [this](const std::string& content){
if(notebook.get_current_page()!=-1) {
auto buffer=notebook.get_current_view()->get_buffer();
try {
auto line=stoul(content);
if(line>0 && line<=(unsigned long)buffer->get_line_count()) {
line--;
buffer->place_cursor(buffer->get_iter_at_line(line));
while(gtk_events_pending())
gtk_main_iteration();
notebook.get_current_view()->scroll_to(buffer->get_insert(), 0.0, 1.0, 0.5);
}
}
catch(const std::exception &e) {}
entry_box.hide();
}
});
auto entry_it=entry_box.entries.begin();
entry_box.buttons.emplace_back("Go to line", [this, entry_it](){
entry_it->activate();
});
entry_box.show();
}
}
void Window::rename_token_entry() { void Window::rename_token_entry() {
entry_box.clear(); entry_box.clear();
if(notebook.get_current_page()!=-1) { if(notebook.get_current_page()!=-1) {

4
src/window.h

@ -10,8 +10,8 @@
class Window : public Gtk::Window { class Window : public Gtk::Window {
public: public:
Window(); Window();
Notebook notebook;
Directories directories; Directories directories;
Notebook notebook;
protected: protected:
bool on_key_press_event(GdkEventKey *event); bool on_key_press_event(GdkEventKey *event);
bool on_delete_event (GdkEventAny *event); bool on_delete_event (GdkEventAny *event);
@ -19,6 +19,7 @@ private:
Gtk::Box box; Gtk::Box box;
Gtk::VPaned vpaned; Gtk::VPaned vpaned;
Gtk::Paned directory_and_notebook_panes; Gtk::Paned directory_and_notebook_panes;
Gtk::VBox notebook_vbox;
Gtk::VBox terminal_vbox; Gtk::VBox terminal_vbox;
Gtk::HBox status_hbox; Gtk::HBox status_hbox;
EntryBox entry_box; EntryBox entry_box;
@ -33,6 +34,7 @@ private:
void save_file_dialog(); void save_file_dialog();
void search_and_replace_entry(); void search_and_replace_entry();
void goto_line_entry();
void rename_token_entry(); void rename_token_entry();
std::string last_search; std::string last_search;
std::string last_replace; std::string last_replace;

Loading…
Cancel
Save