diff --git a/docs/install.md b/docs/install.md index 1505777..8d2d726 100644 --- a/docs/install.md +++ b/docs/install.md @@ -10,8 +10,9 @@ sudo apt-get install clang-format-3.6 || sudo apt-get install clang-format-3.5 Get juCi++ source, compile and install: ```sh git clone --recursive https://github.com/cppit/jucipp -cd jucipp -cmake . +mkdir jucipp/build +cd jucipp/build +cmake .. make sudo make install ``` @@ -25,8 +26,9 @@ sudo apt-get install git cmake make g++ libclang-3.6-dev clang-format-3.6 pkg-co Get juCi++ source, compile and install: ```sh git clone --recursive https://github.com/cppit/jucipp -cd jucipp -cmake . +mkdir jucipp/build +cd jucipp/build +cmake .. make sudo make install ``` @@ -41,8 +43,9 @@ pacman -S git cmake make clang gtksourceviewmm boost aspell aspell-en Get juCi++ source, compile and install: ```sh git clone --recursive https://github.com/cppit/jucipp -cd jucipp -cmake . +mkdir jucipp/build +cd jucipp/build +cmake .. make # as root make install @@ -57,8 +60,9 @@ brew install cmake --with-clang llvm pkg-config boost homebrew/x11/gtksourceview Get juCi++ source, compile and install: ```sh git clone --recursive https://github.com/cppit/jucipp -cd jucipp -cmake . +mkdir jucipp/build +cd jucipp/build +cmake .. make make install ``` @@ -72,8 +76,9 @@ pacman -S git mingw-w64-x86_64-cmake make mingw-w64-x86_64-toolchain mingw-w64-x Get juCi++ source, compile and install (replace `mingw64` with `mingw32` for 32-bit MSYS2 installs): ```sh git clone --recursive https://github.com/cppit/jucipp -cd jucipp -cmake -G"MSYS Makefiles" -DCMAKE_INSTALL_PREFIX=/mingw64 . +mkdir jucipp/build +cd jucipp/build +cmake -G"MSYS Makefiles" -DCMAKE_INSTALL_PREFIX=/mingw64 .. make make install ``` diff --git a/src/cmake.cc b/src/cmake.cc index 620575f..0d8ab02 100644 --- a/src/cmake.cc +++ b/src/cmake.cc @@ -33,19 +33,52 @@ CMake::CMake(const boost::filesystem::path &path) { } if(!project_path.empty()) { - if(boost::filesystem::exists(project_path/"CMakeLists.txt") && !boost::filesystem::exists(project_path/"compile_commands.json")) + auto default_build_path=get_default_build_path(project_path); + if(!default_build_path.empty() && !boost::filesystem::exists(default_build_path/"compile_commands.json")) create_compile_commands(project_path); } } +boost::filesystem::path CMake::get_default_build_path(const boost::filesystem::path &path) { + boost::filesystem::path default_build_path=Config::get().terminal.default_build_path; + + const std::string path_variable_project_directory_name=""; + size_t pos=0; + auto default_build_path_string=default_build_path.string(); + auto path_filename_string=path.filename().string(); + while((pos=default_build_path_string.find(path_variable_project_directory_name, pos))!=std::string::npos) { + default_build_path_string.replace(pos, path_variable_project_directory_name.size(), path_filename_string); + pos+=path_filename_string.size(); + } + if(pos!=0) + default_build_path=default_build_path_string; + + if(default_build_path.is_relative()) + default_build_path=path/default_build_path; + + if(!boost::filesystem::exists(default_build_path)) { + boost::system::error_code ec; + boost::filesystem::create_directories(default_build_path, ec); + if(ec) { + Terminal::get().print("Error: could not create "+default_build_path.string()+": "+ec.message()+"\n", true); + return boost::filesystem::path(); + } + } + + return default_build_path; +} + bool CMake::create_compile_commands(const boost::filesystem::path &path) { - Dialog::Message message("Creating "+path.string()+"/compile_commands.json"); - auto exit_status=Terminal::get().process(Config::get().terminal.cmake_command+" . -DCMAKE_EXPORT_COMPILE_COMMANDS=ON", path); + auto default_build_path=get_default_build_path(path); + if(default_build_path.empty()) + return false; + auto compile_commands_path=default_build_path/"compile_commands.json"; + Dialog::Message message("Creating "+compile_commands_path.string()); + auto exit_status=Terminal::get().process(Config::get().terminal.cmake_command+" "+ + path.string()+" -DCMAKE_EXPORT_COMPILE_COMMANDS=ON", default_build_path); message.hide(); if(exit_status==EXIT_SUCCESS) { #ifdef _WIN32 //Temporary fix to MSYS2's libclang - auto compile_commands_path=path; - compile_commands_path+="/compile_commands.json"; auto compile_commands_file=filesystem::read(compile_commands_path); size_t pos=0; while((pos=compile_commands_file.find("-I/", pos))!=std::string::npos) { diff --git a/src/cmake.h b/src/cmake.h index 8be9d13..e995b23 100644 --- a/src/cmake.h +++ b/src/cmake.h @@ -8,6 +8,7 @@ class CMake { public: CMake(const boost::filesystem::path &path); std::vector > > get_functions_parameters(const std::string &name); + static boost::filesystem::path get_default_build_path(const boost::filesystem::path &path); static bool create_compile_commands(const boost::filesystem::path &path); std::vector paths; @@ -15,6 +16,7 @@ public: boost::filesystem::path project_path; std::unordered_map variables; private: + void read_files(); void remove_tabs(); void remove_comments(); diff --git a/src/config.cc b/src/config.cc index 8663e64..732344f 100644 --- a/src/config.cc +++ b/src/config.cc @@ -36,7 +36,7 @@ void Config::load() { retrieve_config(); } catch(const std::exception &e) { - ::Terminal::get().print("Error reading "+config_json+": "+e.what()+"\n"); + ::Terminal::get().print("Error: could not parse "+config_json+": "+e.what()+"\n", true); std::stringstream ss; ss << configjson; boost::property_tree::read_json(ss, cfg); @@ -84,6 +84,8 @@ void Config::retrieve_config() { window.theme_variant=cfg.get("gtk_theme.variant"); window.version = cfg.get("version"); window.default_size = {cfg.get("default_window_size.width"), cfg.get("default_window_size.height")}; + + terminal.default_build_path=cfg.get("project.default_build_path"); terminal.make_command=cfg.get("project.make_command"); terminal.cmake_command=cfg.get("project.cmake_command"); terminal.history_size=cfg.get("terminal_history_size"); diff --git a/src/config.h b/src/config.h index d86f1d2..6599c3a 100644 --- a/src/config.h +++ b/src/config.h @@ -24,6 +24,7 @@ public: class Terminal { public: + std::string default_build_path; std::string cmake_command; std::string make_command; std::string clang_format_command; diff --git a/src/files.h b/src/files.h index c896e74..1400e0f 100644 --- a/src/files.h +++ b/src/files.h @@ -2,7 +2,7 @@ #define JUCI_FILES_H_ #include -#define JUCI_VERSION "1.0.0" +#define JUCI_VERSION "1.0.1" const std::string configjson = "{\n" @@ -107,6 +107,8 @@ const std::string configjson = " \"close_tab\": \"w\"\n" " },\n" " \"project\": {\n" +" \"default_build_path_comment\": \"Use to insert the project top level directory name\",\n" +" \"default_build_path\": \"./build\",\n" #ifdef _WIN32 " \"cmake_command\": \"cmake -G\\\"MSYS Makefiles\\\" -DCMAKE_INSTALL_PREFIX="+JUCI_CMAKE_INSTALL_PREFIX+"\",\n" #else diff --git a/src/notebook.cc b/src/notebook.cc index 2c62395..f42f022 100644 --- a/src/notebook.cc +++ b/src/notebook.cc @@ -110,7 +110,7 @@ void Notebook::open(const boost::filesystem::path &file_path) { } } if(language && (language->get_id()=="chdr" || language->get_id()=="cpphdr" || language->get_id()=="c" || language->get_id()=="cpp" || language->get_id()=="objc")) { - if(boost::filesystem::exists(project_path.string()+"/CMakeLists.txt") && !boost::filesystem::exists(project_path.string()+"/compile_commands.json")) + if(boost::filesystem::exists(project_path.string()+"/CMakeLists.txt") && !boost::filesystem::exists(CMake::get_default_build_path(project_path)/"compile_commands.json")) CMake::create_compile_commands(project_path); source_views.emplace_back(new Source::ClangView(file_path, project_path, language)); } @@ -248,14 +248,14 @@ bool Notebook::save(int page) { boost::filesystem::path project_path; if(view->file_path.filename()=="CMakeLists.txt") { auto &directories=Directories::get(); - if(directories.cmake && directories.cmake->project_path!="" && view->file_path.generic_string().substr(0, directories.cmake->project_path.generic_string().size()+1)==directories.cmake->project_path.generic_string()+'/' && CMake::create_compile_commands(directories.cmake->project_path)) { - project_path=directories.cmake->project_path; + if(directories.cmake && directories.cmake->project_path!="" && view->file_path.generic_string().substr(0, directories.cmake->project_path.generic_string().size()+1)==directories.cmake->project_path.generic_string()+'/') { + if(CMake::create_compile_commands(directories.cmake->project_path)) + project_path=directories.cmake->project_path; } else { CMake cmake(view->file_path.parent_path()); - if(cmake.project_path!="" && CMake::create_compile_commands(cmake.project_path)) { + if(cmake.project_path!="" && CMake::create_compile_commands(cmake.project_path)) project_path=cmake.project_path; - } } if(project_path!="") { for(auto source_view: source_views) { diff --git a/src/source_clang.cc b/src/source_clang.cc index 338f09c..ef5073c 100644 --- a/src/source_clang.cc +++ b/src/source_clang.cc @@ -1,6 +1,7 @@ #include "source_clang.h" #include "config.h" #include "terminal.h" +#include "cmake.h" namespace sigc { #ifndef SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE @@ -178,7 +179,7 @@ void Source::ClangViewParse::soft_reparse() { } std::vector Source::ClangViewParse::get_compilation_commands() { - clang::CompilationDatabase db(project_path.string()); + clang::CompilationDatabase db(CMake::get_default_build_path(project_path).string()); clang::CompileCommands commands(file_path.string(), db); std::vector cmds = commands.get_commands(); std::vector arguments; @@ -964,26 +965,44 @@ Source::ClangViewAutocomplete(file_path, project_path, language) { auto_indent=[this]() { auto command=Config::get().terminal.clang_format_command; - unsigned indent_width; - std::string tab_style; - if(tab_char=='\t') { - indent_width=tab_size*8; - tab_style="UseTab: Always"; + bool use_style_file=false; + + auto style_file_search_path=this->file_path.parent_path(); + while(true) { + auto style_file=style_file_search_path/"CMakeLists.txt"; + if(boost::filesystem::exists(style_file_search_path/".clang-format") || boost::filesystem::exists(style_file_search_path/"_clang-format")) { + use_style_file=true; + break; + } + if(style_file_search_path==style_file_search_path.root_directory()) + break; + style_file_search_path=style_file_search_path.parent_path(); } + + if(use_style_file) + command+=" -style=file"; else { - indent_width=tab_size; - tab_style="UseTab: Never"; + unsigned indent_width; + std::string tab_style; + if(tab_char=='\t') { + indent_width=tab_size*8; + tab_style="UseTab: Always"; + } + else { + indent_width=tab_size; + tab_style="UseTab: Never"; + } + command+=" -style=\"{IndentWidth: "+std::to_string(indent_width); + command+=", "+tab_style; + command+=", "+std::string("AccessModifierOffset: -")+std::to_string(indent_width); + if(Config::get().source.clang_format_style!="") + command+=", "+Config::get().source.clang_format_style; + command+="}\""; } - command+=" -style=\"{IndentWidth: "+std::to_string(indent_width); - command+=", "+tab_style; - command+=", "+std::string("AccessModifierOffset: -")+std::to_string(indent_width); - if(Config::get().source.clang_format_style!="") - command+=", "+Config::get().source.clang_format_style; - command+="}\""; std::stringstream stdin_stream(get_buffer()->get_text()), stdout_stream; - auto exit_status=Terminal::get().process(stdin_stream, stdout_stream, command); + auto exit_status=Terminal::get().process(stdin_stream, stdout_stream, command, this->file_path.parent_path()); if(exit_status==0) { get_source_buffer()->begin_user_action(); auto iter=get_buffer()->get_insert()->get_iter(); diff --git a/src/terminal.cc b/src/terminal.cc index d1236f8..546328c 100644 --- a/src/terminal.cc +++ b/src/terminal.cc @@ -79,7 +79,7 @@ int Terminal::process(const std::string &command, const boost::filesystem::path process=std::unique_ptr(new Process(command, path.string())); if(process->get_id()<=0) { - async_print("Error: Failed to run command: " + command + "\n", true); + async_print("Error: failed to run command: " + command + "\n", true); return -1; } @@ -101,7 +101,7 @@ int Terminal::process(std::istream &stdin_stream, std::ostream &stdout_stream, c }, true); if(process.get_id()<=0) { - async_print("Error: Failed to run command: " + command + "\n", true); + async_print("Error: failed to run command: " + command + "\n", true); return -1; } @@ -132,7 +132,7 @@ void Terminal::async_process(const std::string &command, const boost::filesystem auto pid=process->get_id(); if (pid<=0) { processes_mutex.unlock(); - async_print("Error: Failed to run command: " + command + "\n", true); + async_print("Error: failed to run command: " + command + "\n", true); if(callback) callback(-1); return; diff --git a/src/window.cc b/src/window.cc index acc4024..38896f4 100644 --- a/src/window.cc +++ b/src/window.cc @@ -539,10 +539,19 @@ void Window::set_menu_actions() { if(cmake.project_path!="") { if(executable_path!="") { + auto project_path=cmake.project_path; + auto default_build_path=CMake::get_default_build_path(project_path); + if(default_build_path.empty()) + return; compiling=true; + auto executable_path_string=executable_path.string(); + size_t pos=executable_path_string.find(project_path.string()); + if(pos!=std::string::npos) { + executable_path_string.replace(pos, project_path.string().size(), default_build_path.string()); + executable_path=executable_path_string; + } Terminal::get().print("Compiling and running "+executable_path.string()+"\n"); - auto project_path=cmake.project_path; - Terminal::get().async_process(Config::get().terminal.make_command, cmake.project_path, [this, executable_path, project_path](int exit_status){ + Terminal::get().async_process(Config::get().terminal.make_command, default_build_path, [this, executable_path, default_build_path](int exit_status){ compiling=false; if(exit_status==EXIT_SUCCESS) { auto executable_path_spaces_fixed=executable_path.string(); @@ -554,7 +563,7 @@ void Window::set_menu_actions() { } last_char=executable_path_spaces_fixed[c]; } - Terminal::get().async_process(executable_path_spaces_fixed, project_path, [this, executable_path](int exit_status){ + Terminal::get().async_process(executable_path_spaces_fixed, default_build_path, [this, executable_path](int exit_status){ Terminal::get().async_print(executable_path.string()+" returned: "+std::to_string(exit_status)+'\n'); }); } @@ -579,9 +588,12 @@ void Window::set_menu_actions() { return; CMake cmake(cmake_path); if(cmake.project_path!="") { + auto default_build_path=CMake::get_default_build_path(cmake.project_path); + if(default_build_path.empty()) + return; compiling=true; Terminal::get().print("Compiling project "+cmake.project_path.string()+"\n"); - Terminal::get().async_process(Config::get().terminal.make_command, cmake.project_path, [this](int exit_status){ + Terminal::get().async_process(Config::get().terminal.make_command, default_build_path, [this](int exit_status){ compiling=false; }); }