Browse Source

Merge branch 'master' of https://github.com/cppit/jucipp

merge-requests/365/head
Jørgen Lien Sellæg 11 years ago
parent
commit
c32f2d95e9
  1. 3
      juci/CMakeLists.txt
  2. 46
      juci/juci.cc
  3. 20
      juci/juci.h
  4. 241
      juci/notebook.cc
  5. 28
      juci/notebook.h
  6. 85
      juci/selectiondialog.cc
  7. 24
      juci/selectiondialog.h
  8. 254
      juci/source.cc
  9. 29
      juci/source.h
  10. 2
      juci/terminal.cc
  11. 11
      juci/window.cc
  12. 1
      juci/window.h

3
juci/CMakeLists.txt

@ -99,6 +99,7 @@ endif()
# name of the executable on Windows will be example.exe # name of the executable on Windows will be example.exe
add_executable(${project_name} add_executable(${project_name}
#list of every needed file to create the executable #list of every needed file to create the executable
juci.h
juci.cc juci.cc
keybindings.h keybindings.h
keybindings.cc keybindings.cc
@ -106,6 +107,8 @@ add_executable(${project_name}
menu.cc menu.cc
source.h source.h
source.cc source.cc
selectiondialog.h
selectiondialog.cc
config.h config.h
config.cc config.cc
sourcefile.h sourcefile.h

46
juci/juci.cc

@ -1,5 +1,4 @@
#include "window.h" #include "juci.h"
#include "logging.h"
void init_logging() { void init_logging() {
add_common_attributes(); add_common_attributes();
@ -8,12 +7,43 @@ void init_logging() {
INFO("Logging initalized"); INFO("Logging initalized");
} }
int Juci::on_command_line(const Glib::RefPtr<Gio::ApplicationCommandLine> &cmd) {
Glib::set_prgname("juci");
Glib::OptionContext ctx("[PATH ...]");
Glib::OptionGroup gtk_group(gtk_get_option_group(true));
ctx.add_group(gtk_group);
int argc;
char **argv = cmd->get_arguments(argc);
ctx.parse(argc, argv);
if(argc>=2) {
for(size_t c=1;c<argc;c++) {
boost::filesystem::path p=boost::filesystem::canonical(argv[c]);
if(boost::filesystem::exists(p)) {
if(boost::filesystem::is_regular_file(p))
files.emplace_back(p.string());
else if(directory=="" && boost::filesystem::is_directory(p))
directory=p.string();
}
}
}
activate();
return 0;
}
void Juci::on_activate() {
window = std::unique_ptr<Window>(new Window());
add_window(*window);
window->show();
if(directory!="") {
//TODO: use the following instead, window->notebook_.open_directory(directory);
window->notebook_.project_path=directory;
window->notebook_.directories.open_folder(directory);
}
for(auto &f: files)
window->notebook_.OnOpenFile(f);
}
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
Glib::RefPtr<Gtk::Application> app = Gtk::Application::create(
argc,
argv,
"no.sout.juci");
init_logging(); init_logging();
Window window; return Juci().run(argc, argv);
return app->run(window);
} }

20
juci/juci.h

@ -0,0 +1,20 @@
#ifndef JUCI_JUCI_H_
#define JUCI_JUCI_H_
#include "window.h"
#include "logging.h"
class Juci : public Gtk::Application {
public:
Juci(): Gtk::Application("no.sout.juci", Gio::APPLICATION_HANDLES_COMMAND_LINE) {}
int on_command_line(const Glib::RefPtr<Gio::ApplicationCommandLine> &cmd);
void on_activate();
private:
std::unique_ptr<Window> window;
std::string directory;
std::vector<std::string> files;
};
#endif // JUCI_JUCI_H_

241
juci/notebook.cc

@ -17,13 +17,12 @@ Notebook::Controller::Controller(Gtk::Window* window,
Keybindings::Controller& keybindings, Keybindings::Controller& keybindings,
Source::Config& source_cfg, Source::Config& source_cfg,
Directories::Config& dir_cfg) : Directories::Config& dir_cfg) :
directories_(dir_cfg), directories(dir_cfg),
source_config_(source_cfg) { source_config(source_cfg) {
INFO("Create notebook"); INFO("Create notebook");
window_ = window; window_ = window;
refClipboard_ = Gtk::Clipboard::get(); refClipboard_ = Gtk::Clipboard::get();
ispopup = false; view().pack1(directories.widget(), true, true);
view().pack1(directories_.widget(), true, true);
CreateKeybindings(keybindings); CreateKeybindings(keybindings);
INFO("Notebook Controller Success"); INFO("Notebook Controller Success");
} // Constructor } // Constructor
@ -32,7 +31,7 @@ Notebook::Controller::Controller(Gtk::Window* window,
void Notebook::Controller::CreateKeybindings(Keybindings::Controller void Notebook::Controller::CreateKeybindings(Keybindings::Controller
&keybindings) { &keybindings) {
INFO("Notebook create signal handlers"); INFO("Notebook create signal handlers");
directories().m_TreeView.signal_row_activated() directories.m_TreeView.signal_row_activated()
.connect(sigc::mem_fun(*this, .connect(sigc::mem_fun(*this,
&Notebook::Controller::OnDirectoryNavigation)); &Notebook::Controller::OnDirectoryNavigation));
@ -176,114 +175,6 @@ void Notebook::Controller::CreateKeybindings(Keybindings::Controller
INFO("Notebook signal handlers sucsess"); INFO("Notebook signal handlers sucsess");
} }
bool Notebook::Controller:: OnMouseRelease(GdkEventButton* button) {
if (button->button == 1 && ispopup) {
popup_.response(Gtk::RESPONSE_DELETE_EVENT);
return true;
}
return false;
}
bool Notebook::Controller::OnKeyRelease(GdkEventKey* key) {
return GeneratePopup(key->keyval);
}
bool Notebook::Controller::GeneratePopup(int key_id) {
INFO("Notebook genereate popup, getting iters");
std::string path = text_vec_.at(CurrentPage())->view->file_path;
if (!source_config().legal_extension(path.substr(path.find_last_of(".") + 1))) return false;
// Get function to fill popup with suggests item vector under is for testing
Gtk::TextIter beg = CurrentTextView().get_buffer()->get_insert()->get_iter();
Gtk::TextIter end = CurrentTextView().get_buffer()->get_insert()->get_iter();
Gtk::TextIter tmp = CurrentTextView().get_buffer()->get_insert()->get_iter();
Gtk::TextIter tmp1 = CurrentTextView().get_buffer()->get_insert()->get_iter();
Gtk::TextIter line =
CurrentTextView().get_buffer()->get_iter_at_line(tmp.get_line());
if (end.backward_char() && end.backward_char()) {
bool illegal_chars =
end.backward_search("\"", Gtk::TEXT_SEARCH_VISIBLE_ONLY, tmp, tmp1, line)
||
end.backward_search("//", Gtk::TEXT_SEARCH_VISIBLE_ONLY, tmp, tmp1, line);
INFO("Notebook genereate popup, checking key_id");
if (illegal_chars) {
return false;
}
std::string c = text_vec_[CurrentPage()]->buffer()->get_text(end, beg);
switch (key_id) {
case 46:
break;
case 58:
if (c != "::") return false;
break;
case 60:
if (c != "->") return false;
break;
case 62:
if (c != "->") return false;
break;
default:
return false;
}
} else {
return false;
}
INFO("Notebook genereate popup, getting autocompletions");
std::vector<Source::AutoCompleteData> acdata=text_vec_.at(CurrentPage())->view->
get_autocomplete_suggestions(beg.get_line()+1,
beg.get_line_offset()+2);
std::map<std::string, std::string> items;
for (auto &data : acdata) {
std::stringstream ss;
std::string return_value;
for (auto &chunk : data.chunks) {
switch (chunk.kind) {
case clang::CompletionChunk_ResultType:
return_value = chunk.chunk;
break;
case clang::CompletionChunk_Informative: break;
default: ss << chunk.chunk; break;
}
}
if (ss.str().length() > 0) { // if length is 0 the result is empty
items[ss.str() + " --> " + return_value] = ss.str();
}
}
Gtk::ScrolledWindow popup_scroll_;
Gtk::ListViewText listview_(1, false, Gtk::SelectionMode::SELECTION_SINGLE);
popup_scroll_.set_policy(Gtk::PolicyType::POLICY_NEVER,
Gtk::PolicyType::POLICY_NEVER);
listview_.set_enable_search(true);
listview_.set_headers_visible(false);
listview_.set_hscroll_policy(Gtk::ScrollablePolicy::SCROLL_NATURAL);
listview_.set_activate_on_single_click(true);
if (items.empty()) {
items["No suggestions found..."] = "";
}
for (auto &i : items) {
listview_.append(i.first);
}
popup_scroll_.add(listview_);
popup_.get_vbox()->pack_start(popup_scroll_);
popup_.set_transient_for(*window_);
popup_.show_all();
INFO("Notebook genereate popup, moving popup");
int popup_x = popup_.get_width();
int popup_y = items.size() * 20;
PopupSetSize(popup_scroll_, popup_x, popup_y);
int x, y;
FindPopupPosition(CurrentTextView(), popup_x, popup_y, x, y);
popup_.move(x, y+15);
INFO("Notebook genereate popup, create handler");
PopupSelectHandler(popup_, listview_, &items);
ispopup = true;
INFO("Notebook genereate popup, run popup");
popup_.run();
INFO("Notebook genereate popup, hide popup");
popup_.hide();
ispopup = false;
return true;
}
Notebook::Controller::~Controller() { Notebook::Controller::~Controller() {
INFO("Notebook destructor"); INFO("Notebook destructor");
for (auto &i : editor_vec_) delete i; for (auto &i : editor_vec_) delete i;
@ -300,7 +191,7 @@ Gtk::Box& Notebook::Controller::entry_view() {
void Notebook::Controller::OnOpenFile(std::string path) { void Notebook::Controller::OnOpenFile(std::string path) {
INFO("Notebook open file"); INFO("Notebook open file");
INFO("Notebook create page"); INFO("Notebook create page");
text_vec_.emplace_back(new Source::Controller(source_config(), path, project_path)); text_vec_.emplace_back(new Source::Controller(source_config, path, project_path));
scrolledtext_vec_.push_back(new Gtk::ScrolledWindow()); scrolledtext_vec_.push_back(new Gtk::ScrolledWindow());
editor_vec_.push_back(new Gtk::HBox()); editor_vec_.push_back(new Gtk::HBox());
scrolledtext_vec_.back()->add(*text_vec_.back()->view); scrolledtext_vec_.back()->add(*text_vec_.back()->view);
@ -313,7 +204,18 @@ void Notebook::Controller::OnOpenFile(std::string path) {
Notebook().show_all_children(); Notebook().show_all_children();
Notebook().set_current_page(Pages()-1); Notebook().set_current_page(Pages()-1);
Notebook().set_focus_child(*text_vec_.back()->view); Notebook().set_focus_child(*text_vec_.back()->view);
set_source_handlers(*text_vec_.back()); //Add star on tab label when the page is not saved:
text_vec_.back()->buffer()->signal_changed().connect([this]() {
if(text_vec_.at(CurrentPage())->is_saved) {
std::string path=text_vec_.at(CurrentPage())->view->file_path;
size_t pos = path.find_last_of("/\\");
std::string filename=path;
if(pos!=std::string::npos)
filename=path.substr(pos+1);
Notebook().set_tab_label_text(*(Notebook().get_nth_page(CurrentPage())), filename+"*");
}
text_vec_.at(CurrentPage())->is_saved=false;
});
} }
void Notebook::Controller::OnCloseCurrentPage() { void Notebook::Controller::OnCloseCurrentPage() {
@ -419,18 +321,18 @@ void Notebook::Controller
::OnDirectoryNavigation(const Gtk::TreeModel::Path& path, ::OnDirectoryNavigation(const Gtk::TreeModel::Path& path,
Gtk::TreeViewColumn* column) { Gtk::TreeViewColumn* column) {
INFO("Notebook directory navigation"); INFO("Notebook directory navigation");
Gtk::TreeModel::iterator iter = directories().m_refTreeModel->get_iter(path); Gtk::TreeModel::iterator iter = directories.m_refTreeModel->get_iter(path);
if (iter) { if (iter) {
Gtk::TreeModel::Row row = *iter; Gtk::TreeModel::Row row = *iter;
std::string upath = Glib::ustring(row[directories().view().m_col_path]); std::string upath = Glib::ustring(row[directories.view().m_col_path]);
boost::filesystem::path fs_path(upath); boost::filesystem::path fs_path(upath);
if (boost::filesystem::is_directory(fs_path)) { if (boost::filesystem::is_directory(fs_path)) {
directories().m_TreeView.row_expanded(path) ? directories.m_TreeView.row_expanded(path) ?
directories().m_TreeView.collapse_row(path) : directories.m_TreeView.collapse_row(path) :
directories().m_TreeView.expand_row(path, false); directories.m_TreeView.expand_row(path, false);
} else { } else {
std::stringstream sstm; std::stringstream sstm;
sstm << row[directories().view().m_col_path]; sstm << row[directories.view().m_col_path];
std::string file = sstm.str(); std::string file = sstm.str();
OnOpenFile(file); OnOpenFile(file);
} }
@ -466,107 +368,10 @@ void Notebook::Controller::BufferChangeHandler(Glib::RefPtr<Gtk::TextBuffer>
}); });
} }
void Notebook::Controller::set_source_handlers(Source::Controller& controller) {
controller.view->signal_button_release_event().
connect(sigc::mem_fun(*this, &Notebook::Controller::OnMouseRelease), false);
controller.view->signal_key_release_event().
connect(sigc::mem_fun(*this, &Notebook::Controller::OnKeyRelease), false);
//Add star on tab label when the page is not saved:
controller.buffer()->signal_changed().connect([this]() {
if(text_vec_.at(CurrentPage())->is_saved) {
std::string path=text_vec_.at(CurrentPage())->view->file_path;
size_t pos = path.find_last_of("/\\");
std::string filename=path;
if(pos!=std::string::npos)
filename=path.substr(pos+1);
Notebook().set_tab_label_text(*(Notebook().get_nth_page(CurrentPage())), filename+"*");
}
text_vec_.at(CurrentPage())->is_saved=false;
});
}
void Notebook::Controller::PopupSelectHandler(Gtk::Dialog &popup,
Gtk::ListViewText &listview,
std::map<std::string, std::string>
*items) {
listview.signal_row_activated().
connect([this, &listview, &popup, items](const Gtk::TreeModel::Path& path,
Gtk::TreeViewColumn*) {
std::string selected = items->
at(listview.get_text(listview.get_selected()[0]));
CurrentTextView().get_buffer()->insert_at_cursor(selected);
popup.response(Gtk::RESPONSE_DELETE_EVENT);
});
}
void Notebook::Controller::PopupSetSize(Gtk::ScrolledWindow &scroll,
int &current_x,
int &current_y) {
INFO("Notebook popup set size");
int textview_x = CurrentTextView().get_width();
int textview_y = 150;
bool is_never_scroll_x = true;
bool is_never_scroll_y = true;
if (current_x > textview_x) {
current_x = textview_x;
is_never_scroll_x = false;
}
if (current_y > textview_y) {
current_y = textview_y;
is_never_scroll_y = false;
}
scroll.set_size_request(current_x, current_y);
if (!is_never_scroll_x && !is_never_scroll_y) {
scroll.set_policy(Gtk::PolicyType::POLICY_AUTOMATIC,
Gtk::PolicyType::POLICY_AUTOMATIC);
} else if (!is_never_scroll_x && is_never_scroll_y) {
scroll.set_policy(Gtk::PolicyType::POLICY_AUTOMATIC,
Gtk::PolicyType::POLICY_NEVER);
} else if (is_never_scroll_x && !is_never_scroll_y) {
scroll.set_policy(Gtk::PolicyType::POLICY_NEVER,
Gtk::PolicyType::POLICY_AUTOMATIC);
}
}
std::string Notebook::Controller::CurrentPagePath(){ std::string Notebook::Controller::CurrentPagePath(){
return text_vec_.at(CurrentPage())->view->file_path; return text_vec_.at(CurrentPage())->view->file_path;
} }
void Notebook::Controller::FindPopupPosition(Gtk::TextView& textview,
int popup_x,
int popup_y,
int &x,
int &y) {
INFO("Notebook popup find position");
Gdk::Rectangle temp1, temp2;
textview.get_cursor_locations(
CurrentTextView().
get_buffer()->get_insert()->
get_iter(), temp1, temp2);
int textview_edge_x = 0;
int textview_edge_y = 0;
textview.buffer_to_window_coords(
Gtk::TextWindowType::TEXT_WINDOW_WIDGET,
temp1.get_x(),
temp1.get_y(),
x, y);
Glib::RefPtr<Gdk::Window> gdkw =
CurrentTextView().get_window(Gtk::TextWindowType::TEXT_WINDOW_WIDGET);
gdkw->get_origin(textview_edge_x, textview_edge_y);
x += textview_edge_x;
y += textview_edge_y;
if ((textview_edge_x-x)*-1 > textview.get_width()-popup_x) {
x -= popup_x;
if (x < textview_edge_x) x = textview_edge_x;
}
if ((textview_edge_y-y)*-1 > textview.get_height()-popup_y) {
y -= (popup_y+14) + 15;
if (x < textview_edge_y) y = textview_edge_y +15;
}
}
bool Notebook::Controller:: OnSaveFile() { bool Notebook::Controller:: OnSaveFile() {
std::string path=text_vec_.at(CurrentPage())->view->file_path; std::string path=text_vec_.at(CurrentPage())->view->file_path;
return OnSaveFile(path); return OnSaveFile(path);

28
juci/notebook.h

@ -61,40 +61,20 @@ namespace Notebook {
void OnOpenFile(std::string filename); void OnOpenFile(std::string filename);
bool ScrollEventCallback(GdkEventScroll* scroll_event); bool ScrollEventCallback(GdkEventScroll* scroll_event);
int Pages(); int Pages();
Directories::Controller& directories() { return directories_; }
Gtk::Paned& view(); Gtk::Paned& view();
bool GeneratePopup(int key);
void Search(bool forward); void Search(bool forward);
Source::Config& source_config() { return source_config_; }
bool OnMouseRelease(GdkEventButton* button);
bool OnKeyRelease(GdkEventKey* key);
std::string OnSaveFileAs(); std::string OnSaveFileAs();
bool LegalExtension(std::string extension);
std::string project_path; std::string project_path;
protected: Directories::Controller directories;
void set_source_handlers(Source::Controller& controller);
void PopupSelectHandler(Gtk::Dialog &popup,
Gtk::ListViewText &listview,
std::map<std::string, std::string>
*items);
private: private:
void CreateKeybindings(Keybindings::Controller& keybindings); void CreateKeybindings(Keybindings::Controller& keybindings);
void FindPopupPosition(Gtk::TextView& textview,
int popup_x,
int popup_y,
int &x,
int &y);
void PopupSetSize(Gtk::ScrolledWindow& scroll,
int &current_x,
int &current_y);
void AskToSaveDialog(); void AskToSaveDialog();
Glib::RefPtr<Gtk::Builder> m_refBuilder; Glib::RefPtr<Gtk::Builder> m_refBuilder;
Glib::RefPtr<Gio::SimpleActionGroup> refActionGroup; Glib::RefPtr<Gio::SimpleActionGroup> refActionGroup;
Source::Config source_config_; Source::Config& source_config;
Directories::Controller directories_;
View view_; View view_;
Model model_; Model model_;
bool is_new_file_; bool is_new_file_; //TODO: Remove this
Entry::Controller entry_; Entry::Controller entry_;
std::vector<std::unique_ptr<Source::Controller> > text_vec_; std::vector<std::unique_ptr<Source::Controller> > text_vec_;
@ -104,8 +84,6 @@ namespace Notebook {
Gtk::TextIter search_match_end_; Gtk::TextIter search_match_end_;
Gtk::TextIter search_match_start_; Gtk::TextIter search_match_start_;
Glib::RefPtr<Gtk::Clipboard> refClipboard_; Glib::RefPtr<Gtk::Clipboard> refClipboard_;
bool ispopup;
Gtk::Dialog popup_;
Gtk::Window* window_; Gtk::Window* window_;
}; // class controller }; // class controller
} // namespace Notebook } // namespace Notebook

85
juci/selectiondialog.cc

@ -0,0 +1,85 @@
#include "selectiondialog.h"
SelectionDialog::SelectionDialog(Gtk::TextView& text_view): Gtk::Dialog(), text_view(text_view),
list_view_text(1, false, Gtk::SelectionMode::SELECTION_SINGLE) {
scrolled_window.set_policy(Gtk::PolicyType::POLICY_NEVER, Gtk::PolicyType::POLICY_NEVER);
list_view_text.set_enable_search(true);
list_view_text.set_headers_visible(false);
list_view_text.set_hscroll_policy(Gtk::ScrollablePolicy::SCROLL_NATURAL);
list_view_text.set_activate_on_single_click(true);
}
void SelectionDialog::show(const std::map<std::string, std::string>& rows) {
for (auto &i : rows) {
list_view_text.append(i.first);
}
scrolled_window.add(list_view_text);
get_vbox()->pack_start(scrolled_window);
set_transient_for((Gtk::Window&)(*text_view.get_toplevel()));
show_all();
int popup_x = get_width();
int popup_y = rows.size() * 20;
adjust(popup_x, popup_y);
list_view_text.signal_row_activated().connect([this](const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn*) {
if(on_select)
on_select(list_view_text);
response(Gtk::RESPONSE_DELETE_EVENT);
});
signal_focus_out_event().connect(sigc::mem_fun(*this, &SelectionDialog::close), false);
run();
}
bool SelectionDialog::close(GdkEventFocus*) {
response(Gtk::RESPONSE_DELETE_EVENT);
return true;
}
void SelectionDialog::adjust(int current_x, int current_y) {
INFO("SelectionDialog set size");
int view_x = text_view.get_width();
int view_y = 150;
bool is_never_scroll_x = true;
bool is_never_scroll_y = true;
if (current_x > view_x) {
current_x = view_x;
is_never_scroll_x = false;
}
if (current_y > view_y) {
current_y = view_y;
is_never_scroll_y = false;
}
scrolled_window.set_size_request(current_x, current_y);
if (!is_never_scroll_x && !is_never_scroll_y) {
scrolled_window.set_policy(Gtk::PolicyType::POLICY_AUTOMATIC, Gtk::PolicyType::POLICY_AUTOMATIC);
} else if (!is_never_scroll_x && is_never_scroll_y) {
scrolled_window.set_policy(Gtk::PolicyType::POLICY_AUTOMATIC, Gtk::PolicyType::POLICY_NEVER);
} else if (is_never_scroll_x && !is_never_scroll_y) {
scrolled_window.set_policy(Gtk::PolicyType::POLICY_NEVER, Gtk::PolicyType::POLICY_AUTOMATIC);
}
INFO("SelectionDialog set position");
Gdk::Rectangle temp1, temp2;
text_view.get_cursor_locations(text_view.get_buffer()->get_insert()->get_iter(), temp1, temp2);
int view_edge_x = 0;
int view_edge_y = 0;
int x, y;
text_view.buffer_to_window_coords(Gtk::TextWindowType::TEXT_WINDOW_WIDGET,
temp1.get_x(), temp1.get_y(), x, y);
Glib::RefPtr<Gdk::Window> gdkw = text_view.get_window(Gtk::TextWindowType::TEXT_WINDOW_WIDGET);
gdkw->get_origin(view_edge_x, view_edge_y);
x += view_edge_x;
y += view_edge_y;
if ((view_edge_x-x)*-1 > text_view.get_width()-current_x) {
x -= current_x;
if (x < view_edge_x) x = view_edge_x;
}
if ((view_edge_y-y)*-1 > text_view.get_height()-current_y) {
y -= (current_y+14) + 15;
if (x < view_edge_y) y = view_edge_y +15;
}
move(x, y+15);
}

24
juci/selectiondialog.h

@ -0,0 +1,24 @@
#ifndef JUCI_SELECTIONDIALOG_H_
#define JUCI_SELECTIONDIALOG_H_
#include "gtkmm.h"
#include "logging.h"
#include "source.h"
class SelectionDialog : public Gtk::Dialog {
public:
SelectionDialog(Gtk::TextView& text_view);
void show(const std::map<std::string, std::string>& rows);
bool close(GdkEventFocus*);
std::function<void(Gtk::ListViewText& list_view_text)> on_select;
private:
void adjust(int current_x, int current_y);
Gtk::TextView& text_view;
Gtk::ScrolledWindow scrolled_window;
Gtk::ListViewText list_view_text;
};
#endif // JUCI_SELECTIONDIALOG_H_

254
juci/source.cc

@ -6,6 +6,7 @@
#include "logging.h" #include "logging.h"
#include <algorithm> #include <algorithm>
#include <regex> #include <regex>
#include "selectiondialog.h"
bool Source::Config::legal_extension(std::string e) const { bool Source::Config::legal_extension(std::string e) const {
std::transform(e.begin(), e.end(),e.begin(), ::tolower); std::transform(e.begin(), e.end(),e.begin(), ::tolower);
@ -20,7 +21,7 @@ bool Source::Config::legal_extension(std::string e) const {
////////////// //////////////
//// View //// //// View ////
////////////// //////////////
Source::View::View(const Config& config, const std::string& file_path, const std::string& project_path): Source::View::View(const Source::Config& config, const std::string& file_path, const std::string& project_path):
config(config), file_path(file_path), project_path(project_path) { config(config), file_path(file_path), project_path(project_path) {
Gsv::init(); Gsv::init();
set_smart_home_end(Gsv::SMART_HOME_END_BEFORE); set_smart_home_end(Gsv::SMART_HOME_END_BEFORE);
@ -49,13 +50,92 @@ string Source::View::get_line_before_insert() {
return line; return line;
} }
//Basic indentation
bool Source::View::on_key_press(GdkEventKey* key) {
const std::regex spaces_regex(std::string("^(")+config.tab_char+"*).*$");
//Indent as in next or previous line
if(key->keyval==GDK_KEY_Return && key->state==0) {
int line_nr=get_source_buffer()->get_insert()->get_iter().get_line();
string line(get_line_before_insert());
std::smatch sm;
if(std::regex_match(line, sm, spaces_regex)) {
if((line_nr+1)<get_source_buffer()->get_line_count()) {
string next_line=get_line(line_nr+1);
std::smatch sm2;
if(std::regex_match(next_line, sm2, spaces_regex)) {
if(sm2[1].str().size()>sm[1].str().size()) {
get_source_buffer()->insert_at_cursor("\n"+sm2[1].str());
scroll_to(get_source_buffer()->get_insert());
return true;
}
}
}
get_source_buffer()->insert_at_cursor("\n"+sm[1].str());
scroll_to(get_source_buffer()->get_insert());
return true;
}
}
//Indent right when clicking tab, no matter where in the line the cursor is. Also works on selected text.
else if(key->keyval==GDK_KEY_Tab && key->state==0) {
Gtk::TextIter selection_start, selection_end;
get_source_buffer()->get_selection_bounds(selection_start, selection_end);
int line_start=selection_start.get_line();
int line_end=selection_end.get_line();
for(int line=line_start;line<=line_end;line++) {
Gtk::TextIter line_it = get_source_buffer()->get_iter_at_line(line);
get_source_buffer()->insert(line_it, config.tab);
}
return true;
}
//Indent left when clicking shift-tab, no matter where in the line the cursor is. Also works on selected text.
else if((key->keyval==GDK_KEY_ISO_Left_Tab || key->keyval==GDK_KEY_Tab) && key->state==GDK_SHIFT_MASK) {
Gtk::TextIter selection_start, selection_end;
get_source_buffer()->get_selection_bounds(selection_start, selection_end);
int line_start=selection_start.get_line();
int line_end=selection_end.get_line();
for(int line_nr=line_start;line_nr<=line_end;line_nr++) {
string line=get_line(line_nr);
if(!(line.size()>=config.tab_size && line.substr(0, config.tab_size)==config.tab))
return true;
}
for(int line_nr=line_start;line_nr<=line_end;line_nr++) {
Gtk::TextIter line_it = get_source_buffer()->get_iter_at_line(line_nr);
Gtk::TextIter line_plus_it=line_it;
for(unsigned c=0;c<config.tab_size;c++)
line_plus_it++;
get_source_buffer()->erase(line_it, line_plus_it);
}
return true;
}
//"Smart" backspace key
else if(key->keyval==GDK_KEY_BackSpace) {
Gtk::TextIter insert_it=get_source_buffer()->get_insert()->get_iter();
int line_nr=insert_it.get_line();
if(line_nr>0) {
string line=get_line(line_nr);
string previous_line=get_line(line_nr-1);
smatch sm;
if(std::regex_match(previous_line, sm, spaces_regex)) {
if(line==sm[1] || line==(std::string(sm[1])+config.tab) || (line+config.tab==sm[1])) {
Gtk::TextIter line_it = get_source_buffer()->get_iter_at_line(line_nr);
get_source_buffer()->erase(line_it, insert_it);
}
}
}
}
return false;
}
////////////////// //////////////////
//// ClangView /// //// ClangView ///
////////////////// //////////////////
clang::Index Source::ClangView::clang_index(0, 1); clang::Index Source::ClangView::clang_index(0, 1);
Source::ClangView::ClangView(const Config& config, const std::string& file_path, const std::string& project_path): Source::ClangView::ClangView(const Source::Config& config, const std::string& file_path, const std::string& project_path):
Source::View::View(config, file_path, project_path), Source::View(config, file_path, project_path),
parse_thread_go(true), parse_thread_mapped(false), parse_thread_stop(false) { parse_thread_go(true), parse_thread_mapped(false), parse_thread_stop(false) {
override_font(Pango::FontDescription(config.font)); override_font(Pango::FontDescription(config.font));
override_background_color(Gdk::RGBA(config.background)); override_background_color(Gdk::RGBA(config.background));
@ -119,6 +199,7 @@ parse_thread_go(true), parse_thread_mapped(false), parse_thread_stop(false) {
}); });
signal_key_press_event().connect(sigc::mem_fun(*this, &Source::ClangView::on_key_press), false); signal_key_press_event().connect(sigc::mem_fun(*this, &Source::ClangView::on_key_press), false);
signal_key_release_event().connect(sigc::mem_fun(*this, &Source::ClangView::on_key_release), false);
} }
Source::ClangView::~ClangView() { Source::ClangView::~ClangView() {
@ -181,7 +262,7 @@ get_autocomplete_suggestions(int line_number, int column) {
std::vector<std::string> Source::ClangView:: std::vector<std::string> Source::ClangView::
get_compilation_commands() { get_compilation_commands() {
clang::CompilationDatabase db(project_path+"/"); clang::CompilationDatabase db(project_path);
clang::CompileCommands commands(file_path, &db); clang::CompileCommands commands(file_path, &db);
std::vector<clang::CompileCommand> cmds = commands.get_commands(); std::vector<clang::CompileCommand> cmds = commands.get_commands();
std::vector<std::string> arguments; std::vector<std::string> arguments;
@ -275,33 +356,118 @@ highlight_token(clang::Token *token,
end_offset), token_kind); end_offset), token_kind);
} }
//TODO: replace indentation methods with a better implementation or bool Source::ClangView::on_key_release(GdkEventKey* key) {
//maybe use libclang INFO("Source::ClangView::on_key_release getting iters");
// Get function to fill popup with suggests item vector under is for testing
Gtk::TextIter beg = get_source_buffer()->get_insert()->get_iter();
Gtk::TextIter end = get_source_buffer()->get_insert()->get_iter();
Gtk::TextIter tmp = get_source_buffer()->get_insert()->get_iter();
Gtk::TextIter tmp1 = get_source_buffer()->get_insert()->get_iter();
Gtk::TextIter line = get_source_buffer()->get_iter_at_line(tmp.get_line());
if (end.backward_char() && end.backward_char()) {
bool illegal_chars =
end.backward_search("\"", Gtk::TEXT_SEARCH_VISIBLE_ONLY, tmp, tmp1, line)
||
end.backward_search("//", Gtk::TEXT_SEARCH_VISIBLE_ONLY, tmp, tmp1, line);
INFO("Source::ClangView::on_key_release checking key->keyval");
if (illegal_chars) {
return false;
}
std::string c = get_source_buffer()->get_text(end, beg);
switch (key->keyval) {
case 46:
break;
case 58:
if (c != "::") return false;
break;
case 60:
if (c != "->") return false;
break;
case 62:
if (c != "->") return false;
break;
default:
return false;
}
} else {
return false;
}
INFO("Source::ClangView::on_key_release getting autocompletions");
std::vector<Source::AutoCompleteData> acdata=get_autocomplete_suggestions(beg.get_line()+1,
beg.get_line_offset()+2);
std::map<std::string, std::string> rows;
for (auto &data : acdata) {
std::stringstream ss;
std::string return_value;
for (auto &chunk : data.chunks) {
switch (chunk.kind) {
case clang::CompletionChunk_ResultType:
return_value = chunk.chunk;
break;
case clang::CompletionChunk_Informative: break;
default: ss << chunk.chunk; break;
}
}
if (ss.str().length() > 0) { // if length is 0 the result is empty
rows[ss.str() + " --> " + return_value] = ss.str();
}
}
if (rows.empty()) {
rows["No suggestions found..."] = "";
}
SelectionDialog selection_dialog(*this);
selection_dialog.on_select=[this, &rows](Gtk::ListViewText& list_view_text){
std::string selected = rows.at(list_view_text.get_text(list_view_text.get_selected()[0]));
get_source_buffer()->insert_at_cursor(selected);
};
selection_dialog.show(rows);
return true;
}
//Clang indentation
//TODO: replace indentation methods with a better implementation or maybe use libclang
bool Source::ClangView::on_key_press(GdkEventKey* key) { bool Source::ClangView::on_key_press(GdkEventKey* key) {
const std::regex bracket_regex("^( *).*\\{ *$"); const std::regex bracket_regex(std::string("^(")+config.tab_char+"*).*\\{ *$");
const std::regex no_bracket_statement_regex("^( *)(if|for|else if|catch|while) *\\(.*[^;}] *$"); 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("^( *)(else|try|do) *$"); const std::regex no_bracket_no_para_statement_regex(std::string("^(")+config.tab_char+"*)(else|try|do) *$");
const std::regex spaces_regex("^( *).*$"); const std::regex spaces_regex(std::string("^(")+config.tab_char+"*).*$");
//Indent as in previous line, and indent right after if/else/etc //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) {
string line(get_line_before_insert()); string line(get_line_before_insert());
std::smatch sm; std::smatch sm;
if(std::regex_match(line, sm, bracket_regex)) { if(std::regex_match(line, sm, bracket_regex)) {
size_t line_nr=get_source_buffer()->get_insert()->get_iter().get_line();
if((line_nr+1)<get_source_buffer()->get_line_count()) {
string next_line=get_line(line_nr+1);
std::smatch sm2;
if(std::regex_match(next_line, sm2, spaces_regex)) {
if(sm2[1].str()==sm[1].str()+config.tab) {
get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+config.tab);
scroll_to(get_source_buffer()->get_insert());
return true;
}
}
}
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()+config.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<config.tab_size+sm[1].str().size();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);
return true;
} }
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()+config.tab);
scroll_to(get_source_buffer()->get_insert()); scroll_to(get_source_buffer()->get_insert());
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()+config.tab);
scroll_to(get_source_buffer()->get_insert()); scroll_to(get_source_buffer()->get_insert());
return true;
} }
else if(std::regex_match(line, sm, spaces_regex)) { else if(std::regex_match(line, sm, spaces_regex)) {
std::smatch sm2; std::smatch sm2;
@ -321,52 +487,14 @@ bool Source::ClangView::on_key_press(GdkEventKey* key) {
} }
} }
} }
get_source_buffer()->insert_at_cursor("\n"+sm[1].str());
scroll_to(get_source_buffer()->get_insert());
}
return true;
}
//Indent right when clicking tab, no matter where in the line the cursor is. Also works on selected text.
if(key->keyval==GDK_KEY_Tab && key->state==0) {
Gtk::TextIter selection_start, selection_end;
get_source_buffer()->get_selection_bounds(selection_start, selection_end);
int line_start=selection_start.get_line();
int line_end=selection_end.get_line();
for(int line=line_start;line<=line_end;line++) {
Gtk::TextIter line_it = get_source_buffer()->get_iter_at_line(line);
get_source_buffer()->insert(line_it, config.tab);
} }
return true;
}
//Indent left when clicking shift-tab, no matter where in the line the cursor is. Also works on selected text.
else if((key->keyval==GDK_KEY_ISO_Left_Tab || key->keyval==GDK_KEY_Tab) && key->state==GDK_SHIFT_MASK) {
Gtk::TextIter selection_start, selection_end;
get_source_buffer()->get_selection_bounds(selection_start, selection_end);
int line_start=selection_start.get_line();
int line_end=selection_end.get_line();
for(int line_nr=line_start;line_nr<=line_end;line_nr++) {
string line=get_line(line_nr);
if(!(line.size()>=config.tab_size && line.substr(0, config.tab_size)==config.tab))
return true;
}
for(int line_nr=line_start;line_nr<=line_end;line_nr++) {
Gtk::TextIter line_it = get_source_buffer()->get_iter_at_line(line_nr);
Gtk::TextIter line_plus_it=line_it;
for(unsigned c=0;c<config.tab_size;c++)
line_plus_it++;
get_source_buffer()->erase(line_it, line_plus_it);
}
return true;
} }
//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()>=config.tab_size) {
for(auto c: line) { for(auto c: line) {
if(c!=' ') if(c!=config.tab_char)
return false; return false;
} }
Gtk::TextIter insert_it = get_source_buffer()->get_insert()->get_iter(); Gtk::TextIter insert_it = get_source_buffer()->get_insert()->get_iter();
@ -379,23 +507,8 @@ bool Source::ClangView::on_key_press(GdkEventKey* key) {
} }
return false; return false;
} }
//"Smart" backspace key
else if(key->keyval==GDK_KEY_BackSpace) { return Source::View::on_key_press(key);
Gtk::TextIter insert_it=get_source_buffer()->get_insert()->get_iter();
int line_nr=insert_it.get_line();
if(line_nr>0) {
string line=get_line(line_nr);
string previous_line=get_line(line_nr-1);
smatch sm;
if(std::regex_match(previous_line, sm, spaces_regex)) {
if(line==sm[1]) {
Gtk::TextIter line_it = get_source_buffer()->get_iter_at_line(line_nr);
get_source_buffer()->erase(line_it, insert_it);
}
}
}
}
return false;
} }
//////////////////// ////////////////////
@ -405,12 +518,9 @@ bool Source::ClangView::on_key_press(GdkEventKey* key) {
// Source::Controller::Controller() // Source::Controller::Controller()
// Constructor for Controller // Constructor for Controller
Source::Controller::Controller(const Source::Config &config, Source::Controller::Controller(const Source::Config &config,
const std::string& file_path, std::string project_path) : const std::string& file_path, std::string project_path) {
config(config) {
if(project_path=="") { if(project_path=="") {
size_t last_of=file_path.find_last_of("\\/"); project_path=boost::filesystem::path(file_path).parent_path().string();
if(last_of!=std::string::npos)
project_path=file_path.substr(0, last_of);
} }
if (config.legal_extension(file_path.substr(file_path.find_last_of(".") + 1))) if (config.legal_extension(file_path.substr(file_path.find_last_of(".") + 1)))
view=std::unique_ptr<View>(new ClangView(config, file_path, project_path)); view=std::unique_ptr<View>(new ClangView(config, file_path, project_path));

29
juci/source.h

@ -11,10 +11,6 @@
#include <atomic> #include <atomic>
#include "gtksourceviewmm.h" #include "gtksourceviewmm.h"
namespace Notebook {
class Controller;
}
namespace Source { namespace Source {
class Config { class Config {
public: public:
@ -22,6 +18,7 @@ namespace Source {
unsigned tab_size; unsigned tab_size;
bool show_line_numbers, highlight_current_line; bool show_line_numbers, highlight_current_line;
std::string tab, background, font; std::string tab, background, font;
char tab_char=' ';
std::vector<std::string> extensions; std::vector<std::string> extensions;
std::unordered_map<std::string, std::string> tags, types; std::unordered_map<std::string, std::string> tags, types;
}; // class Config }; // class Config
@ -60,25 +57,31 @@ namespace Source {
class View : public Gsv::View { class View : public Gsv::View {
public: public:
View(const Config& config, const std::string& file_path, const std::string& project_path); View(const Source::Config& config, const std::string& file_path, const std::string& project_path);
std::string get_line(size_t line_number); std::string get_line(size_t line_number);
std::string get_line_before_insert(); std::string get_line_before_insert();
virtual std::vector<Source::AutoCompleteData> get_autocomplete_suggestions(int line_number, int column) {return std::vector<Source::AutoCompleteData>();}
std::string file_path; std::string file_path;
std::string project_path; std::string project_path;
protected: protected:
const Config& config; const Source::Config& config;
bool on_key_press(GdkEventKey* key);
}; // class View }; // class View
class GenericView : public View { class GenericView : public View {
public: public:
GenericView(const Config& config, const std::string& file_path, const std::string& project_path): GenericView(const Source::Config& config, const std::string& file_path, const std::string& project_path):
View(config, file_path, project_path) {} View(config, file_path, project_path) {
signal_key_press_event().connect(sigc::mem_fun(*this, &Source::GenericView::on_key_press), false);
}
private:
bool on_key_press(GdkEventKey* key) {
return Source::View::on_key_press(key);
}
}; };
class ClangView : public View { class ClangView : public View {
public: public:
ClangView(const Config& config, const std::string& file_path, const std::string& project_path); ClangView(const Source::Config& config, const std::string& file_path, const std::string& project_path);
~ClangView(); ~ClangView();
// inits the syntax highligthing on file open // inits the syntax highligthing on file open
void init_syntax_highlighting(const std::map<std::string, std::string> void init_syntax_highlighting(const std::map<std::string, std::string>
@ -103,6 +106,7 @@ namespace Source {
std::vector<Range> *source_ranges); std::vector<Range> *source_ranges);
std::vector<std::string> get_compilation_commands(); std::vector<std::string> get_compilation_commands();
bool on_key_press(GdkEventKey* key); bool on_key_press(GdkEventKey* key);
bool on_key_release(GdkEventKey* key);
Glib::Dispatcher parse_done; Glib::Dispatcher parse_done;
Glib::Dispatcher parse_start; Glib::Dispatcher parse_start;
@ -122,10 +126,7 @@ namespace Source {
bool is_saved = true; bool is_saved = true;
std::unique_ptr<View> view; std::unique_ptr<Source::View> view;
private:
const Config& config;
}; // class Controller }; // class Controller
} // namespace Source } // namespace Source
#endif // JUCI_SOURCE_H_ #endif // JUCI_SOURCE_H_

2
juci/terminal.cc

@ -87,11 +87,9 @@ void Terminal::Controller::ExecuteCommand(std::string command, std::string mode)
FILE* p = NULL; FILE* p = NULL;
std::cout << command << std::endl; std::cout << command << std::endl;
p = popen(command.c_str(), mode.c_str()); p = popen(command.c_str(), mode.c_str());
std::cout << "KJØRTE FINT!" << std::endl;
if (p == NULL) { if (p == NULL) {
PrintMessage("juCi++ ERROR: Failed to run command" + command + "\n"); PrintMessage("juCi++ ERROR: Failed to run command" + command + "\n");
}else { }else {
std::cout << "SKRIVER UT KOMMANDO RESULAT" << std::endl;
char buffer[1028]; char buffer[1028];
while (fgets(buffer, 1028, p) != NULL) { while (fgets(buffer, 1028, p) != NULL) {
PrintMessage(buffer); PrintMessage(buffer);

11
juci/window.cc

@ -73,7 +73,7 @@ Window::Window() :
terminal_.SetFolderCommand(path); terminal_.SetFolderCommand(path);
} }
terminal_.Compile(); terminal_.Compile();
std::string executable = notebook_.directories(). std::string executable = notebook_.directories.
GetCmakeVarValue(path,"add_executable"); GetCmakeVarValue(path,"add_executable");
terminal_.Run(executable); terminal_.Run(executable);
running.unlock(); running.unlock();
@ -104,10 +104,6 @@ Window::Window() :
execute.detach(); execute.detach();
} }
}); });
this->signal_button_release_event().
connect(sigc::mem_fun(*this,&Window::OnMouseRelease),false);
terminal_.Terminal().signal_button_release_event().
connect(sigc::mem_fun(*this,&Window::OnMouseRelease),false);
add_accel_group(keybindings_.ui_manager_menu()->get_accel_group()); add_accel_group(keybindings_.ui_manager_menu()->get_accel_group());
add_accel_group(keybindings_.ui_manager_hidden()->get_accel_group()); add_accel_group(keybindings_.ui_manager_hidden()->get_accel_group());
@ -144,7 +140,7 @@ void Window::OnFileOpenFolder() {
{ {
std::string project_path=dialog.get_filename(); std::string project_path=dialog.get_filename();
notebook_.project_path=project_path; notebook_.project_path=project_path;
notebook_.directories().open_folder(project_path); notebook_.directories.open_folder(project_path);
break; break;
} }
case(Gtk::RESPONSE_CANCEL): case(Gtk::RESPONSE_CANCEL):
@ -203,9 +199,6 @@ void Window::OnOpenFile() {
} }
} }
} }
bool Window::OnMouseRelease(GdkEventButton *button){
return notebook_.OnMouseRelease(button);
}
bool Window::SaveFile() { bool Window::SaveFile() {
if(notebook_.OnSaveFile()) { if(notebook_.OnSaveFile()) {

1
juci/window.h

@ -32,7 +32,6 @@ public:
void OnWindowHide(); void OnWindowHide();
void OnOpenFile(); void OnOpenFile();
void OnFileOpenFolder(); void OnFileOpenFolder();
bool OnMouseRelease(GdkEventButton* button);
bool SaveFile(); bool SaveFile();
bool SaveFileAs(); bool SaveFileAs();
}; };

Loading…
Cancel
Save