From f7efa11cdddd32ff6525603b10cc5782b1a613c2 Mon Sep 17 00:00:00 2001 From: "U-olece-PC\\olece" Date: Thu, 20 Aug 2015 15:09:31 +0200 Subject: [PATCH 01/54] terminal now works on Cygwin. --- src/terminal.cc | 50 ++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/terminal.cc b/src/terminal.cc index d47b9be..4df8e24 100644 --- a/src/terminal.cc +++ b/src/terminal.cc @@ -11,7 +11,7 @@ using namespace std; //TODO: remove //TODO: Windows... //A working implementation of popen3, with all pipes getting closed properly. //TODO: Eidheim is going to publish this one on his github, along with example uses -pid_t popen3(const char *command, int &stdin, int &stdout, int &stderr) { +pid_t popen3(const char *command, int &stdin_fd, int &stdout_fd, int &stderr_fd) { pid_t pid; int p_stdin[2], p_stdout[2], p_stderr[2]; @@ -56,9 +56,9 @@ pid_t popen3(const char *command, int &stdin, int &stdout, int &stderr) { close(p_stdout[1]); close(p_stderr[1]); - stdin = p_stdin[1]; - stdout = p_stdout[0]; - stderr = p_stderr[0]; + stdin_fd = p_stdin[1]; + stdout_fd = p_stdout[0]; + stderr_fd = p_stderr[0]; return pid; } @@ -145,18 +145,18 @@ int Terminal::execute(const std::string &command, const boost::filesystem::path else cd_path_and_command=command; - int stdin, stdout, stderr; - auto pid=popen3(cd_path_and_command.c_str(), stdin, stdout, stderr); + int stdin_fd, stdout_fd, stderr_fd; + auto pid=popen3(cd_path_and_command.c_str(), stdin_fd, stdout_fd, stderr_fd); if (pid<=0) { async_print("Error: Failed to run command: " + command + "\n"); return -1; } else { - std::thread stderr_thread([this, stderr](){ + std::thread stderr_thread([this, stderr_fd](){ char buffer[1024]; ssize_t n; - while ((n=read(stderr, buffer, 1024)) > 0) { + while ((n=read(stderr_fd, buffer, 1024)) > 0) { std::string message; for(ssize_t c=0;c 0) { + while ((n=read(stdout_fd, buffer, 1024)) > 0) { std::string message; for(ssize_t c=0;c 0) { + while ((n=read(stderr_fd, buffer, 1024)) > 0) { std::string message; for(ssize_t c=0;c 0) { + while ((n=read(stdout_fd, buffer, 1024)) > 0) { std::string message; for(ssize_t c=0;c Date: Fri, 21 Aug 2015 12:44:24 +0200 Subject: [PATCH 02/54] Fixed a couple indenting issues around brackets. --- src/source.cc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/source.cc b/src/source.cc index 06672c8..fb223b8 100644 --- a/src/source.cc +++ b/src/source.cc @@ -874,7 +874,9 @@ bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) { return true; } } - if(next_line!=sm[1].str()+"}") { + auto next_char=*get_buffer()->get_insert()->get_iter(); + auto next_line_with_end_bracket=sm[1].str()+"}"; + if(next_char!='}' && next_line.substr(0, next_line_with_end_bracket.size())!=next_line_with_end_bracket) { get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+tab+"\n"+sm[1].str()+"}"); auto insert_it = get_source_buffer()->get_insert()->get_iter(); for(size_t c=0;cend_user_action(); return true; } + else if(next_char=='}') { + get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+tab+"\n"+sm[1].str()); + auto insert_it = get_source_buffer()->get_insert()->get_iter(); + for(size_t c=0;cget_insert()); + get_source_buffer()->place_cursor(insert_it); + get_source_buffer()->end_user_action(); + return true; + } else { get_source_buffer()->insert_at_cursor("\n"+sm[1].str()+tab); scroll_to(get_source_buffer()->get_insert()); From d977cfa03260fbfd7169f82df663496cb3a77e38 Mon Sep 17 00:00:00 2001 From: "U-ole-PC\\ole" Date: Sat, 22 Aug 2015 12:03:42 +0200 Subject: [PATCH 03/54] Cygwin-support added, please note that I have not yet tested the changes on OS X and Debian. Doing it now. --- CMakeLists.txt | 6 +-- docs/install.md | 57 ++++++++++++++++++++------ src/CMakeLists.txt | 45 ++++++++++++-------- src/cmake/Modules/FindLibClangmm.cmake | 14 +++++-- src/window.cc | 4 +- 5 files changed, 87 insertions(+), 39 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index da710eb..efaa283 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,13 +1,13 @@ cmake_minimum_required (VERSION 2.8.4) set(project_name juci) -set(module juci_to_python_api) +#set(module juci_to_python_api) #### TODO WINDOWS SUPPORT #### set(bin_install_path "/usr/local/bin") -set(lib_install_path "/usr/local/lib/python2.7/dist-packages/") +#set(lib_install_path "/usr/local/lib/python2.7/dist-packages/") ##### project (${project_name}) -add_subdirectory("src") \ No newline at end of file +add_subdirectory("src") diff --git a/docs/install.md b/docs/install.md index 345a815..042ab50 100644 --- a/docs/install.md +++ b/docs/install.md @@ -1,22 +1,55 @@ # juCi++ ## Installation guide ## -Before installation, please install libclangmm see [installation guide](http://github.com/cppit/libclangmm/blob/master/docs/install.md) for installation. +Before installation, please install libclangmm, see [installation guide](http://github.com/cppit/libclangmm/blob/master/docs/install.md). + ## Debian -First dependencies: ```sh -$ sudo apt-get install libboost-python-dev libboost-filesystem-dev libboost-log-dev libboost-test-dev -libboost-thread-dev libboost-system-dev libgtkmm-3.0-dev libgtksourceview2.0-dev libgtksourceviewmm-3.0-dev -libpython-dev libclang-dev make cmake gcc g++ +sudo apt-get install pkg-config libboost-system-dev libboost-thread-dev libboost-filesystem-dev libboost-log-dev libgtkmm-3.0-dev libgtksourceviewmm-3.0-dev ``` -Install the project: ```sh -$ git clone http://github.com/cppit/jucipp.git juci -$ cd juci -$ cmake . -$ make -$ sudo make install +git clone http://github.com/cppit/jucipp.git +cd jucipp +cmake . +make +sudo make install ``` + +## OS X with Homebrew (http://brew.sh/) +```sh +brew install pkg-config boost gtkmm3 gtksourceviewmm3 +``` + +```sh +git clone https://github.com/cppit/jucipp.git +cd jucipp +cmake . +make +make install +``` + +## Windows with Cygwin (https://www.cygwin.com/) +**Make sure the PATH environment variable does not include paths to non-Cygwin cmake, make and g++.** +Select and install the following packages from the Cygwin-installer: +``` +pkg-config libboost-devel libgtkmm3.0-devel libgtksourceviewmm3.0-devel xinit +``` +Then run the following in the Cygwin Terminal: +```sh +git clone https://github.com/cppit/jucipp.git +cd jucipp +cmake . +make +make install +``` + +Note that we are currently working on a Windows-version without the need of an X-server. + ## Run ```sh -$ juci +juci +``` + +#Windows +```sh +startxwin /usr/local/bin/juci ``` diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5f892eb..c2bda6f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -7,6 +7,11 @@ if(APPLE) set(CMAKE_MACOSX_RPATH 1) set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:/usr/local/lib/pkgconfig:/opt/X11/lib/pkgconfig") endif() + +if(CYGWIN) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mwindows") #TODO: make juci work with -mwin32 to run without X-server +endif() + INCLUDE(FindPkgConfig) set(validation true) @@ -21,7 +26,7 @@ function(install_help APPLE UNIX WINDOWS) endif(APPLE) endif(UNIX) if(WINDOWS) - message("choco install ${WINDOWS}") + #message("choco install ${WINDOWS}") #Removed this for the time being endif(WINDOWS) endfunction(install_help) @@ -38,10 +43,11 @@ validate(${LCL_FOUND} "clangmm" "clangmm" "clangmm") find_package(LibClang) validate(${LIBCLANG_FOUND} "clang" "libclang-dev" "llvm") -find_package(PythonLibs 2.7) -validate(${PYTHONLIBS_FOUND} "python" "libpython-dev" "python") +#find_package(PythonLibs 2.7) +#validate(${PYTHONLIBS_FOUND} "python" "libpython-dev" "python") -find_package(Boost 1.55 COMPONENTS python thread log system filesystem REQUIRED) +#find_package(Boost 1.55 COMPONENTS python thread log system filesystem REQUIRED) +find_package(Boost 1.55 COMPONENTS thread log system filesystem REQUIRED) validate(${Boost_FOUND} "boost" "libboost-all-dev" "boost") pkg_check_modules(GTKMM gtkmm-3.0) # The name GTKMM is set here for the variables abouve @@ -66,8 +72,8 @@ if(${validation}) sourcefile.cc window.cc window.h - api.h - api.cc +# api.h +# api.cc notebook.cc notebook.h entrybox.h @@ -83,13 +89,13 @@ if(${validation}) cmake.h cmake.cc) - add_library(${module} SHARED - api - api_ext) +# add_library(${module} SHARED +# api +# api_ext) include_directories( ${Boost_INCLUDE_DIRS} - ${PYTHON_INCLUDE_DIRS} +# ${PYTHON_INCLUDE_DIRS} ${GTKMM_INCLUDE_DIRS} ${GTKSVMM_INCLUDE_DIRS} ${LCL_INCLUDE_DIRS} @@ -99,15 +105,16 @@ if(${validation}) ${GTKMM_LIBRARY_DIRS} ${GTKSVMM_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS} - ${PYTHON_INCLUDE_DIRS} +# ${PYTHON_INCLUDE_DIRS} ${LCL_LIBRARY_DIRS} ${LIBCLANG_LIBRARY_DIRS}) - set_target_properties(${module} - PROPERTIES PREFIX "" - LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/lib/") +# set_target_properties(${module} +# PROPERTIES PREFIX "" +# LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/lib/") - target_link_libraries(${module} ${PYTHON_LIBRARIES} ${Boost_LIBRARIES}) +# target_link_libraries(${module} ${PYTHON_LIBRARIES} ${Boost_LIBRARIES}) +# target_link_libraries(${module} ${Boost_LIBRARIES}) target_link_libraries(${project_name} ${LIBCLANG_LIBRARIES} @@ -115,11 +122,13 @@ if(${validation}) ${GTKMM_LIBRARIES} ${GTKSVMM_LIBRARIES} ${Boost_LIBRARIES} - ${PYTHON_LIBRARIES}) +# ${PYTHON_LIBRARIES} + ) - install(TARGETS ${project_name} ${module} +# install(TARGETS ${project_name} ${module} + install(TARGETS ${project_name} RUNTIME DESTINATION ${bin_install_path} - LIBRARY DESTINATION ${lib_install_path} +# LIBRARY DESTINATION ${lib_install_path} ) endif(${validation}) diff --git a/src/cmake/Modules/FindLibClangmm.cmake b/src/cmake/Modules/FindLibClangmm.cmake index 49f950b..c8e7f65 100644 --- a/src/cmake/Modules/FindLibClangmm.cmake +++ b/src/cmake/Modules/FindLibClangmm.cmake @@ -5,12 +5,18 @@ find_package(PkgConfig) find_path(LCL_INCLUDE_DIR clangmm.h - HINTS "/usr/local/include/libclangmm/" - ) + HINTS /usr/local/include/libclangmm +) + + +if(CYGWIN) + set(CMAKE_FIND_LIBRARY_PREFIXES ${CMAKE_FIND_LIBRARY_PREFIXES} "cyg") + set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES} ".dll") +endif() find_library(LCL_LIBRARY NAMES clangmm - HINTS "/usr/local/lib/" - ) + PATHS /usr/local/lib /usr/local/bin +) set(LCL_LIBRARIES ${LCL_LIBRARY} ) set(LCL_INCLUDE_DIRS ${LCL_INCLUDE_DIR} ) diff --git a/src/window.cc b/src/window.cc index 2aa0100..ebd1cff 100644 --- a/src/window.cc +++ b/src/window.cc @@ -3,7 +3,7 @@ #include "singletons.h" #include "sourcefile.h" #include "config.h" -#include "api.h" +//#include "api.h" #include #include //TODO: remove @@ -30,7 +30,7 @@ Window::Window() : box(Gtk::ORIENTATION_VERTICAL), notebook(directories), compil add(box); generate_keybindings(); - PluginApi(&this->notebook, &this->menu); + //PluginApi(&this->notebook, &this->menu); create_menu(); box.pack_start(menu.get_widget(), Gtk::PACK_SHRINK); From 4afeb5339c87e70afaa58655766d31c0257a7a5c Mon Sep 17 00:00:00 2001 From: eidheim Date: Sat, 22 Aug 2015 12:12:07 +0200 Subject: [PATCH 04/54] Tested and works with debian and OS X. --- docs/install.md | 2 +- src/cmake/Modules/FindLibClang.cmake | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/install.md b/docs/install.md index 042ab50..f7f4f99 100644 --- a/docs/install.md +++ b/docs/install.md @@ -49,7 +49,7 @@ Note that we are currently working on a Windows-version without the need of an X juci ``` -#Windows +###Windows ```sh startxwin /usr/local/bin/juci ``` diff --git a/src/cmake/Modules/FindLibClang.cmake b/src/cmake/Modules/FindLibClang.cmake index 3d15636..f294979 100644 --- a/src/cmake/Modules/FindLibClang.cmake +++ b/src/cmake/Modules/FindLibClang.cmake @@ -14,7 +14,8 @@ # Known LLVM release numbers. # most recent versions come first -set(LIBCLANG_KNOWN_LLVM_VERSIONS 3.6.1 +set(LIBCLANG_KNOWN_LLVM_VERSIONS 3.6.2 + 3.6.1 3.6 3.5.1 3.5.0 #Arch Linux From c10077b02a5e8299c53ffdc735743beb24c79086 Mon Sep 17 00:00:00 2001 From: Ole Christian Eidheim Date: Sat, 22 Aug 2015 12:13:37 +0200 Subject: [PATCH 05/54] Update install.md --- docs/install.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/install.md b/docs/install.md index f7f4f99..933673a 100644 --- a/docs/install.md +++ b/docs/install.md @@ -49,7 +49,7 @@ Note that we are currently working on a Windows-version without the need of an X juci ``` -###Windows +## Windows ```sh startxwin /usr/local/bin/juci ``` From 0f0c943efb83a5e65515676d0e96054617f75356 Mon Sep 17 00:00:00 2001 From: Ole Christian Eidheim Date: Sat, 22 Aug 2015 12:14:27 +0200 Subject: [PATCH 06/54] Update install.md --- docs/install.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/install.md b/docs/install.md index 933673a..3aed74e 100644 --- a/docs/install.md +++ b/docs/install.md @@ -49,7 +49,7 @@ Note that we are currently working on a Windows-version without the need of an X juci ``` -## Windows +#### Windows ```sh startxwin /usr/local/bin/juci ``` From d45a80a0694aa0a3f9642933e992407d863404ca Mon Sep 17 00:00:00 2001 From: Ole Christian Eidheim Date: Sat, 22 Aug 2015 12:15:03 +0200 Subject: [PATCH 07/54] Update install.md --- docs/install.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/install.md b/docs/install.md index 3aed74e..d24fd88 100644 --- a/docs/install.md +++ b/docs/install.md @@ -45,6 +45,7 @@ make install Note that we are currently working on a Windows-version without the need of an X-server. ## Run +#### Linux/OS X ```sh juci ``` From 6bccc417fbbf52a86b5abeba27b136c79ed5b20f Mon Sep 17 00:00:00 2001 From: Ole Christian Eidheim Date: Sat, 22 Aug 2015 12:32:48 +0200 Subject: [PATCH 08/54] Update install.md --- docs/install.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/install.md b/docs/install.md index d24fd88..eb9a248 100644 --- a/docs/install.md +++ b/docs/install.md @@ -2,7 +2,7 @@ ## Installation guide ## Before installation, please install libclangmm, see [installation guide](http://github.com/cppit/libclangmm/blob/master/docs/install.md). -## Debian +## Debian/Ubuntu ```sh sudo apt-get install pkg-config libboost-system-dev libboost-thread-dev libboost-filesystem-dev libboost-log-dev libgtkmm-3.0-dev libgtksourceviewmm-3.0-dev ``` @@ -29,6 +29,7 @@ make install ## Windows with Cygwin (https://www.cygwin.com/) **Make sure the PATH environment variable does not include paths to non-Cygwin cmake, make and g++.** + Select and install the following packages from the Cygwin-installer: ``` pkg-config libboost-devel libgtkmm3.0-devel libgtksourceviewmm3.0-devel xinit From aa50a94a006115df4620868449cd9197edb869f7 Mon Sep 17 00:00:00 2001 From: eidheim Date: Sat, 22 Aug 2015 13:45:12 +0200 Subject: [PATCH 09/54] Added cmake_command to config.json so that one can use the MinGW toolchain in Windows if that is wanted. Also now shows all files in directory (some files like cmake.cc got hidden before). --- src/CMakeLists.txt | 2 +- src/cmake.cc | 2 +- src/config.cc | 3 ++- src/files.h | 7 +------ src/terminal.h | 1 + 5 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c2bda6f..3118301 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -9,7 +9,7 @@ if(APPLE) endif() if(CYGWIN) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mwindows") #TODO: make juci work with -mwin32 to run without X-server + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mwindows") endif() INCLUDE(FindPkgConfig) diff --git a/src/cmake.cc b/src/cmake.cc index d2ecfe6..aab2338 100644 --- a/src/cmake.cc +++ b/src/cmake.cc @@ -47,7 +47,7 @@ CMake::CMake(const boost::filesystem::path &path) { bool CMake::create_compile_commands(const boost::filesystem::path &path) { Singleton::terminal()->print("Creating "+path.string()+"/compile_commands.json\n"); //TODO: Windows... - if(Singleton::terminal()->execute("cmake . -DCMAKE_EXPORT_COMPILE_COMMANDS=ON", path)==EXIT_SUCCESS) + if(Singleton::terminal()->execute(Singleton::Config::terminal()->cmake_command+" . -DCMAKE_EXPORT_COMPILE_COMMANDS=ON", path)==EXIT_SUCCESS) return true; return false; } diff --git a/src/config.cc b/src/config.cc index f41feb4..0de059c 100644 --- a/src/config.cc +++ b/src/config.cc @@ -14,8 +14,9 @@ MainConfig::MainConfig() { Singleton::Config::window()->theme_name=cfg.get("gtk_theme.name"); Singleton::Config::window()->theme_variant=cfg.get("gtk_theme.variant"); - + Singleton::Config::terminal()->make_command=cfg.get("project.make_command"); + Singleton::Config::terminal()->cmake_command=cfg.get("project.cmake_command"); } void MainConfig::find_or_create_config_files() { diff --git a/src/files.h b/src/files.h index 9112019..a706c2f 100644 --- a/src/files.h +++ b/src/files.h @@ -62,18 +62,13 @@ const std::string configjson = " \"force_kill_last_running\": \"Escape\"\n" " },\n" " \"project\": {\n" +" \"cmake_command\": \"cmake\",\n" " \"make_command\": \"make\"\n" " },\n" " \"directoryfilter\": {\n" " \"ignore\": [\n" -" \"cmake\",\n" -" \"#\",\n" -" \"~\",\n" -" \".idea\",\n" -" \".so\"\n" " ],\n" " \"exceptions\": [\n" -" \"cmakelists.txt\"\n" " ]\n" " }\n" "}\n"; diff --git a/src/terminal.h b/src/terminal.h index 5bdbe1a..dfd1f50 100644 --- a/src/terminal.h +++ b/src/terminal.h @@ -13,6 +13,7 @@ class Terminal : public Gtk::TextView { public: class Config { public: + std::string cmake_command; std::string make_command; }; From eedb344d7ea3408fa1bd73e1a2ad3594a8e33cc4 Mon Sep 17 00:00:00 2001 From: "U-olece-PC\\olece" Date: Sat, 22 Aug 2015 14:31:11 +0200 Subject: [PATCH 10/54] Fixed tooltip issue on Windows. --- src/source.cc | 25 ++++++++++++++----------- src/source.h | 2 ++ 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/source.cc b/src/source.cc index fb223b8..24c3d1a 100644 --- a/src/source.cc +++ b/src/source.cc @@ -794,18 +794,21 @@ void Source::ClangViewParse::update_types() { } bool Source::ClangViewParse::on_motion_notify_event(GdkEventMotion* event) { - delayed_tooltips_connection.disconnect(); - if(clang_readable && event->state==0) { - Gdk::Rectangle rectangle(event->x, event->y, 1, 1); - Tooltips::init(); - type_tooltips.show(rectangle); - diagnostic_tooltips.show(rectangle); - } - else { - type_tooltips.hide(); - diagnostic_tooltips.hide(); + if(on_motion_last_x!=event->x || on_motion_last_y!=event->y) { + delayed_tooltips_connection.disconnect(); + if(clang_readable && event->state==0) { + Gdk::Rectangle rectangle(event->x, event->y, 1, 1); + Tooltips::init(); + type_tooltips.show(rectangle); + diagnostic_tooltips.show(rectangle); + } + else { + type_tooltips.hide(); + diagnostic_tooltips.hide(); + } } - + on_motion_last_x=event->x; + on_motion_last_y=event->y; return Source::View::on_motion_notify_event(event); } diff --git a/src/source.h b/src/source.h index ee4a4ec..c374dfc 100644 --- a/src/source.h +++ b/src/source.h @@ -132,6 +132,8 @@ namespace Source { Tooltips diagnostic_tooltips; Tooltips type_tooltips; bool on_motion_notify_event(GdkEventMotion* event); + gdouble on_motion_last_x; + gdouble on_motion_last_y; void on_mark_set(const Gtk::TextBuffer::iterator& iterator, const Glib::RefPtr& mark); bool on_scroll_event(GdkEventScroll* event); From d892f7386f50843b2430f60e55ed6058ab5a353b Mon Sep 17 00:00:00 2001 From: eidheim Date: Sun, 23 Aug 2015 08:53:24 +0200 Subject: [PATCH 11/54] Improved README.md. --- README.md | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 3823f43..40ec707 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,22 @@ # juCi++ ###### a lightweight C++-IDE with support for C++11 and C++14. ## About -A lot of IDEs struggle with good C++11/14 support. Therefore we -created juCi++. juCi++ is based of the compiler and will *always* -support new versions of C++. +Current IDEs struggle with C++ support due to the complexity of +the programming language. juCI++, however, is designed especially +towards libclang with speed in mind. ## Features -* Syntax highlighing (even C++11/14) -* Superfast autocomletion (even external libraries) +* Fast and responsive +* Syntax highlighing (even C++11/14, and 118 other file types) +* C++ warnings and errors on the fly +* Fast C++ autocomletion (even external libraries) +* Tooltips showing type information and doxygen documentation * Accurate refactoring across files * Basic editor functionallity * Highlighting of similar types -* write your own plugins in python (limited atm) +* Write your own plugins in python (disabled at the moment) ## Dependencies ## -Please install these dependencies on your system. -* libboost-python-dev * libboost-filesystem-dev * libboost-log-dev * libboost-test-dev @@ -24,19 +25,8 @@ Please install these dependencies on your system. * libgtkmm-3.0-dev * libgtksourceview2.0-dev * libgtksourceviewmm-3.0-dev -* libpython-dev * libclang-dev * [libclangmm](http://github.com/cppit/libclangmm/) -* cmake -* make -* clang or gcc (compiler) ## Installation ## -Quickstart: -```sh -$ cmake . -$ make -$ sudo make install -``` -See [installation guide](http://github.com/cppit/jucipp/blob/master/docs/install.md) for more details. - +See [installation guide](http://github.com/cppit/jucipp/blob/master/docs/install.md). From d9a1f7805ba94924a484b16c25a80262aa3c825b Mon Sep 17 00:00:00 2001 From: eidheim Date: Sun, 23 Aug 2015 10:52:34 +0200 Subject: [PATCH 12/54] Fixed double click to select whole variable in Linux. --- src/source.cc | 22 ++++++++++++++++++++++ src/source.h | 1 + 2 files changed, 23 insertions(+) diff --git a/src/source.cc b/src/source.cc index 24c3d1a..eb2b65e 100644 --- a/src/source.cc +++ b/src/source.cc @@ -390,6 +390,28 @@ bool Source::View::on_key_press_event(GdkEventKey* key) { return stop; } +bool Source::View::on_button_press_event(GdkEventButton *event) { + if(event->type==GDK_2BUTTON_PRESS) { + Gtk::TextIter start, end; + if(get_buffer()->get_selection_bounds(start, end)) { + auto iter=start; + while((*iter>=48 && *iter<=57) || (*iter>=65 && *iter<=90) || (*iter>=97 && *iter<=122) || *iter==95) { + start=iter; + if(!iter.backward_char()) + break; + } + while((*end>=48 && *end<=57) || (*end>=65 && *end<=90) || (*end>=97 && *end<=122) || *end==95) { + if(!end.forward_char()) + break; + } + get_buffer()->select_range(start, end); + return true; + } + } + + return Gsv::View::on_button_press_event(event); +} + std::pair Source::View::find_tab_char_and_size() { const std::regex indent_regex("^([ \t]+).*$"); auto size=get_buffer()->get_line_count(); diff --git a/src/source.h b/src/source.h index c374dfc..e51ff3d 100644 --- a/src/source.h +++ b/src/source.h @@ -80,6 +80,7 @@ namespace Source { std::string get_line_before_insert(); bool on_key_press_event(GdkEventKey* key); + bool on_button_press_event(GdkEventButton *event); std::pair find_tab_char_and_size(); unsigned tab_size; From 8175836db1ba1bab8319a756854bcd6cce62c580 Mon Sep 17 00:00:00 2001 From: eidheim Date: Sun, 23 Aug 2015 11:05:36 +0200 Subject: [PATCH 13/54] Added slight delay on mouse-pointer tooltips. --- src/source.cc | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/source.cc b/src/source.cc index eb2b65e..f02d005 100644 --- a/src/source.cc +++ b/src/source.cc @@ -818,16 +818,21 @@ void Source::ClangViewParse::update_types() { bool Source::ClangViewParse::on_motion_notify_event(GdkEventMotion* event) { if(on_motion_last_x!=event->x || on_motion_last_y!=event->y) { delayed_tooltips_connection.disconnect(); - if(clang_readable && event->state==0) { - Gdk::Rectangle rectangle(event->x, event->y, 1, 1); - Tooltips::init(); - type_tooltips.show(rectangle); - diagnostic_tooltips.show(rectangle); - } - else { - type_tooltips.hide(); - diagnostic_tooltips.hide(); + if(event->state==0) { + gdouble x=event->x; + gdouble y=event->y; + delayed_tooltips_connection=Glib::signal_timeout().connect([this, x, y]() { + if(clang_readable) { + Gdk::Rectangle rectangle(x, y, 1, 1); + Tooltips::init(); + type_tooltips.show(rectangle); + diagnostic_tooltips.show(rectangle); + } + return false; + }, 100); } + type_tooltips.hide(); + diagnostic_tooltips.hide(); } on_motion_last_x=event->x; on_motion_last_y=event->y; From fce4b93961ab0372bf4a0fbdc58c8f6438597275 Mon Sep 17 00:00:00 2001 From: "U-olece-PC\\olece" Date: Mon, 24 Aug 2015 14:33:41 +0200 Subject: [PATCH 14/54] Added MINGW-packages for gtksourceview3 and gtksourceviewmm3 (3.12.0). --- .../0006-hack-convert-path-back-to-unix.patch | 15 +++++ .../mingw-w64-gtksourceview3/PKGBUILD | 64 +++++++++++++++++++ .../mingw-w64-gtksourceviewmm3/PKGBUILD | 33 ++++++++++ 3 files changed, 112 insertions(+) create mode 100644 MINGW-packages/mingw-w64-gtksourceview3/0006-hack-convert-path-back-to-unix.patch create mode 100644 MINGW-packages/mingw-w64-gtksourceview3/PKGBUILD create mode 100644 MINGW-packages/mingw-w64-gtksourceviewmm3/PKGBUILD diff --git a/MINGW-packages/mingw-w64-gtksourceview3/0006-hack-convert-path-back-to-unix.patch b/MINGW-packages/mingw-w64-gtksourceview3/0006-hack-convert-path-back-to-unix.patch new file mode 100644 index 0000000..68f217f --- /dev/null +++ b/MINGW-packages/mingw-w64-gtksourceview3/0006-hack-convert-path-back-to-unix.patch @@ -0,0 +1,15 @@ +--- gtksourceview-3.13.90/configure.ac.orig 2014-08-22 00:42:28.532000000 +0400 ++++ gtksourceview-3.13.90/configure.ac 2014-08-22 00:43:00.621200000 +0400 +@@ -133,6 +133,12 @@ + AC_MSG_RESULT([$GLADE_CATALOG_DIR]) + AC_SUBST(GLADE_CATALOG_DIR)]) + ++case "$host" in ++ *-*-mingw*) ++ GLADE_CATALOG_DIR=`cygpath -u $GLADE_CATALOG_DIR` ++ ;; ++esac ++ + # i18N stuff + IT_PROG_INTLTOOL([0.40]) + AS_IF([test "$USE_NLS" = "yes"], diff --git a/MINGW-packages/mingw-w64-gtksourceview3/PKGBUILD b/MINGW-packages/mingw-w64-gtksourceview3/PKGBUILD new file mode 100644 index 0000000..038333a --- /dev/null +++ b/MINGW-packages/mingw-w64-gtksourceview3/PKGBUILD @@ -0,0 +1,64 @@ +# Maintainer: Alexey Pavlov + +_realname=gtksourceview +pkgname="${MINGW_PACKAGE_PREFIX}-${_realname}3" +pkgver=3.12.0 +pkgrel=2 +pkgdesc="A text widget adding syntax highlighting and more to GNOME (mingw-w64)" +arch=('any') +url="http://www.gnome.org" +license=("LGPL") +makedepends=("${MINGW_PACKAGE_PREFIX}-gcc" + "${MINGW_PACKAGE_PREFIX}-pkg-config" + "${MINGW_PACKAGE_PREFIX}-gobject-introspection" + "${MINGW_PACKAGE_PREFIX}-glade" + "${MINGW_PACKAGE_PREFIX}-vala" + "intltool" + "gtk-doc") +depends=("${MINGW_PACKAGE_PREFIX}-gtk3" + "${MINGW_PACKAGE_PREFIX}-libxml2") +options=(!libtool strip staticlibs) +source=("http://ftp.gnome.org/pub/gnome/sources/gtksourceview/${pkgver%.*}/gtksourceview-${pkgver}.tar.xz" + 0006-hack-convert-path-back-to-unix.patch) +md5sums=('8850fc0aee4893668ede37a30ef05e85' + '324c9e3bb2e4fa2a4977653ce6ed6ef9') + +prepare() { + cd ${_realname}-${pkgver} + patch -p1 -i ${srcdir}/0006-hack-convert-path-back-to-unix.patch + + autoreconf -fi +} + +build() { + mkdir -p "${srcdir}/build-${MINGW_CHOST}" + cd "${srcdir}/build-${MINGW_CHOST}" + + mkdir -p docs/reference/html + cp -rf ../${_realname}-${pkgver}/docs/reference/html/* docs/reference/html + + DATADIRNAME=share \ + ../${_realname}-${pkgver}/configure \ + --prefix=${MINGW_PREFIX} \ + --build=${MINGW_CHOST} \ + --host=${MINGW_CHOST} \ + --enable-shared \ + --disable-static \ + --enable-glade-catalog + + LC_ALL=C make +} + +package() { + cd "${srcdir}/build-${MINGW_CHOST}" + make -j1 DESTDIR="${pkgdir}" install + + for ff in ${pkgdir}/${MINGW_PREFIX}/bin/libgtksourceview*.dll; do + local _reallib=$(basename $ff) + _reallib=${_reallib%.dll} + _reallib=${_reallib#lib} + sed -e "s|library=\"gtksourceview-3.0\"|library=\"${_reallib}\"|g" -i ${pkgdir}/${MINGW_PREFIX}/share/glade/catalogs/gtksourceview.xml + done + + install -Dm644 "${srcdir}/${_realname}-${pkgver}/COPYING" "${pkgdir}${MINGW_PREFIX}/share/licenses/${_realname}/COPYING" +} diff --git a/MINGW-packages/mingw-w64-gtksourceviewmm3/PKGBUILD b/MINGW-packages/mingw-w64-gtksourceviewmm3/PKGBUILD new file mode 100644 index 0000000..e76c572 --- /dev/null +++ b/MINGW-packages/mingw-w64-gtksourceviewmm3/PKGBUILD @@ -0,0 +1,33 @@ +_realname=gtksourceviewmm3 +pkgname="${MINGW_PACKAGE_PREFIX}-${_realname}" +pkgver=3.12.0 +pkgrel=1 +pkgdesc="C++ bindings for gtksourceview3 (mingw-w64)" +arch=('any') +url="https://developer.gnome.org/gtksourceviewmm/" +license=("LGPL") +makedepends=("patch" "${MINGW_PACKAGE_PREFIX}-gcc" "${MINGW_PACKAGE_PREFIX}-pkg-config") +depends=("${MINGW_PACKAGE_PREFIX}-gtksourceview3=3.12.0") +options=('staticlibs' 'strip') +source=("https://download.gnome.org/sources/gtksourceviewmm/${pkgver%.*}/gtksourceviewmm-${pkgver}.tar.xz") +sha256sums=("73939031bcc60e6ad31a315ec84b132deba15e5732de16e75fe424a619267ace") + +build() { + mkdir -p "${srcdir}/build-${MINGW_CHOST}" + cd "${srcdir}/build-${MINGW_CHOST}" + ../gtksourceviewmm-${pkgver}/configure \ + CXXFLAGS=-std=c++11 \ + --prefix=${MINGW_PREFIX} \ + --build=${MINGW_CHOST} \ + --host=${MINGW_CHOST} \ + --enable-shared \ + --enable-static \ + --disable-documentation + make +} + +package() { + cd "${srcdir}/build-${MINGW_CHOST}" + make DESTDIR="${pkgdir}" install + find "${pkgdir}${MINGW_PREFIX}" -name '*.def' -o -name '*.exp' | xargs -rtl1 rm +} \ No newline at end of file From ddc0fddc97f6e8208693a5fb173f4ea3d9502927 Mon Sep 17 00:00:00 2001 From: "U-olece-PC\\olece" Date: Mon, 24 Aug 2015 14:36:59 +0200 Subject: [PATCH 15/54] Minor change to dependency check. --- MINGW-packages/mingw-w64-gtksourceviewmm3/PKGBUILD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MINGW-packages/mingw-w64-gtksourceviewmm3/PKGBUILD b/MINGW-packages/mingw-w64-gtksourceviewmm3/PKGBUILD index e76c572..0d842a8 100644 --- a/MINGW-packages/mingw-w64-gtksourceviewmm3/PKGBUILD +++ b/MINGW-packages/mingw-w64-gtksourceviewmm3/PKGBUILD @@ -7,7 +7,7 @@ arch=('any') url="https://developer.gnome.org/gtksourceviewmm/" license=("LGPL") makedepends=("patch" "${MINGW_PACKAGE_PREFIX}-gcc" "${MINGW_PACKAGE_PREFIX}-pkg-config") -depends=("${MINGW_PACKAGE_PREFIX}-gtksourceview3=3.12.0") +depends=("${MINGW_PACKAGE_PREFIX}-gtksourceview3=${pkgver}") options=('staticlibs' 'strip') source=("https://download.gnome.org/sources/gtksourceviewmm/${pkgver%.*}/gtksourceviewmm-${pkgver}.tar.xz") sha256sums=("73939031bcc60e6ad31a315ec84b132deba15e5732de16e75fe424a619267ace") From ae09be013673ededdd658263e85ecf128ae39707 Mon Sep 17 00:00:00 2001 From: "U-olece-PC\\olece" Date: Mon, 24 Aug 2015 14:41:52 +0200 Subject: [PATCH 16/54] Added license file. --- MINGW-packages/LICENSE | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 MINGW-packages/LICENSE diff --git a/MINGW-packages/LICENSE b/MINGW-packages/LICENSE new file mode 100644 index 0000000..e0f07ba --- /dev/null +++ b/MINGW-packages/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2013, Алексей +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + +* Neither the name of the {organization} nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. From 8991a4725b83fddfd3c353f70ad5c5301b52d7da Mon Sep 17 00:00:00 2001 From: "U-olece-PC\\olece" Date: Mon, 24 Aug 2015 14:45:54 +0200 Subject: [PATCH 17/54] gtk_file_chooser_set_filename now works on Windows. --- src/window.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/window.cc b/src/window.cc index ebd1cff..bba2e52 100644 --- a/src/window.cc +++ b/src/window.cc @@ -493,7 +493,7 @@ void Window::save_file_dialog() { return; INFO("Save file dialog"); Gtk::FileChooserDialog dialog(*this, "Please choose a file", Gtk::FILE_CHOOSER_ACTION_SAVE); - gtk_file_chooser_set_filename((GtkFileChooser*)dialog.gobj(), notebook.get_current_view()->file_path.c_str()); + gtk_file_chooser_set_filename((GtkFileChooser*)dialog.gobj(), notebook.get_current_view()->file_path.string().c_str()); dialog.set_position(Gtk::WindowPosition::WIN_POS_CENTER_ALWAYS); dialog.add_button("Cancel", Gtk::RESPONSE_CANCEL); dialog.add_button("Save", Gtk::RESPONSE_OK); From 7d06001e690f0fb549a72eecccd82f69931af590 Mon Sep 17 00:00:00 2001 From: "U-olece-PC\\olece" Date: Mon, 24 Aug 2015 15:43:34 +0200 Subject: [PATCH 18/54] Removed Cygwin, added MSYS2 with TODOs. --- docs/install.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/install.md b/docs/install.md index eb9a248..7c2c456 100644 --- a/docs/install.md +++ b/docs/install.md @@ -27,6 +27,13 @@ make make install ``` +##Windows with MSYS2 (https://msys2.github.io/) +Will be available when the following TODOs are resolved: +* Newlines are saved properly +* Windows implementation of fork/pipe/read/write +* libclang(mm) finds header-files + + ## Run #### Linux/OS X @@ -51,7 +59,9 @@ Note that we are currently working on a Windows-version without the need of an X juci ``` + \ No newline at end of file From dd14202ad89db49196dfa0d650e81a97601a33f3 Mon Sep 17 00:00:00 2001 From: "U-olece-PC\\olece" Date: Mon, 24 Aug 2015 16:00:56 +0200 Subject: [PATCH 19/54] CMakeFiles are now working in Windows. --- CMakeLists.txt | 10 +++++++--- src/CMakeLists.txt | 8 ++++---- src/cmake/Modules/FindLibClangmm.cmake | 18 ++++++++++-------- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index efaa283..045f920 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,10 +3,14 @@ cmake_minimum_required (VERSION 2.8.4) set(project_name juci) #set(module juci_to_python_api) -#### TODO WINDOWS SUPPORT #### -set(bin_install_path "/usr/local/bin") +if(MSYS) + string(TOLOWER "/$ENV{MSYSTEM}" MSYS_PATH) + set(bin_install_path "${MSYS_PATH}/bin") +else() + set(bin_install_path "/usr/local/bin") +endif() + #set(lib_install_path "/usr/local/lib/python2.7/dist-packages/") -##### project (${project_name}) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3118301..5a53998 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,10 +8,6 @@ if(APPLE) set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:/usr/local/lib/pkgconfig:/opt/X11/lib/pkgconfig") endif() -if(CYGWIN) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mwindows") -endif() - INCLUDE(FindPkgConfig) set(validation true) @@ -43,6 +39,10 @@ validate(${LCL_FOUND} "clangmm" "clangmm" "clangmm") find_package(LibClang) validate(${LIBCLANG_FOUND} "clang" "libclang-dev" "llvm") +if(MSYS) + set(LIBCLANG_LIBRARIES "${MSYS_PATH}/bin/clang.dll") +endif() + #find_package(PythonLibs 2.7) #validate(${PYTHONLIBS_FOUND} "python" "libpython-dev" "python") diff --git a/src/cmake/Modules/FindLibClangmm.cmake b/src/cmake/Modules/FindLibClangmm.cmake index c8e7f65..9ba851d 100644 --- a/src/cmake/Modules/FindLibClangmm.cmake +++ b/src/cmake/Modules/FindLibClangmm.cmake @@ -4,20 +4,22 @@ find_package(PkgConfig) +if(MSYS) + string(TOLOWER "/$ENV{MSYSTEM}" MSYS_PATH) + set(MSYS_INCLUDE_PATH "${MSYS_PATH}/include/libclangmm") + set(MSYS_BIN_PATH "${MSYS_PATH}/bin") +endif() + find_path(LCL_INCLUDE_DIR clangmm.h - HINTS /usr/local/include/libclangmm + PATHS /usr/local/include/libclangmm ${MSYS_INCLUDE_PATH} ) - -if(CYGWIN) - set(CMAKE_FIND_LIBRARY_PREFIXES ${CMAKE_FIND_LIBRARY_PREFIXES} "cyg") - set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES} ".dll") -endif() - find_library(LCL_LIBRARY NAMES clangmm - PATHS /usr/local/lib /usr/local/bin + PATHS /usr/local/lib ${MSYS_BIN_PATH} ) +message("${LCL_INCLUDE_DIR}") + set(LCL_LIBRARIES ${LCL_LIBRARY} ) set(LCL_INCLUDE_DIRS ${LCL_INCLUDE_DIR} ) From 08d1bc7de80b5e674a03d3b0dd8d3bb407932a2c Mon Sep 17 00:00:00 2001 From: "U-olece-PC\\olece" Date: Mon, 24 Aug 2015 16:02:07 +0200 Subject: [PATCH 20/54] Removed debug message. --- src/cmake/Modules/FindLibClangmm.cmake | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/cmake/Modules/FindLibClangmm.cmake b/src/cmake/Modules/FindLibClangmm.cmake index 9ba851d..ff7c8cb 100644 --- a/src/cmake/Modules/FindLibClangmm.cmake +++ b/src/cmake/Modules/FindLibClangmm.cmake @@ -18,8 +18,6 @@ find_library(LCL_LIBRARY NAMES clangmm PATHS /usr/local/lib ${MSYS_BIN_PATH} ) -message("${LCL_INCLUDE_DIR}") - set(LCL_LIBRARIES ${LCL_LIBRARY} ) set(LCL_INCLUDE_DIRS ${LCL_INCLUDE_DIR} ) From 62830656202af71f409e85fc7d395b773c0483e8 Mon Sep 17 00:00:00 2001 From: eidheim Date: Mon, 24 Aug 2015 20:28:04 +0200 Subject: [PATCH 21/54] Added terminal_win.cc for Windows. --- src/CMakeLists.txt | 14 +- src/terminal_win.cc | 311 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 321 insertions(+), 4 deletions(-) create mode 100644 src/terminal_win.cc diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5a53998..d15e8e1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -56,9 +56,7 @@ validate(${GTKMM_FOUND} "gtkmm" "libgtkmm-dev" "gtkmm") pkg_check_modules(GTKSVMM gtksourceviewmm-3.0) validate(${GTKSVMM_FOUND} "gtksvmm" "libgtksvmm-dev" "gtkmmsv") -if(${validation}) - add_executable(${project_name} - juci.h +set(source_files juci.h juci.cc menu.h menu.cc @@ -81,7 +79,6 @@ if(${validation}) directories.h directories.cc terminal.h - terminal.cc tooltips.h tooltips.cc singletons.h @@ -89,6 +86,15 @@ if(${validation}) cmake.h cmake.cc) +if(MSYS) + list(APPEND source_files terminal_win.cc) +else() + list(APPEND source_files terminal.cc) +endif() + +if(${validation}) + add_executable(${project_name} ${source_files}) + # add_library(${module} SHARED # api # api_ext) diff --git a/src/terminal_win.cc b/src/terminal_win.cc new file mode 100644 index 0000000..b6a7fdb --- /dev/null +++ b/src/terminal_win.cc @@ -0,0 +1,311 @@ +#include "terminal.h" +#include +#include "logging.h" +#include "singletons.h" +#include + +#include //TODO: remove +using namespace std; //TODO: remove + +Terminal::InProgress::InProgress(const std::string& start_msg): stop(false) { + waiting_print.connect([this](){ + Singleton::terminal()->async_print(line_nr-1, "."); + }); + start(start_msg); +} + +Terminal::InProgress::~InProgress() { + stop=true; + if(wait_thread.joinable()) + wait_thread.join(); +} + +void Terminal::InProgress::start(const std::string& msg) { + line_nr=Singleton::terminal()->print(msg+"...\n"); + wait_thread=std::thread([this](){ + size_t c=0; + while(!stop) { + if(c%100==0) + waiting_print(); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + c++; + } + }); +} + +void Terminal::InProgress::done(const std::string& msg) { + if(!stop) { + stop=true; + Singleton::terminal()->async_print(line_nr-1, msg); + } +} + +void Terminal::InProgress::cancel(const std::string& msg) { + if(!stop) { + stop=true; + Singleton::terminal()->async_print(line_nr-1, msg); + } +} + +Terminal::Terminal() { + bold_tag=get_buffer()->create_tag(); + bold_tag->property_weight()=PANGO_WEIGHT_BOLD; + + signal_size_allocate().connect([this](Gtk::Allocation& allocation){ + auto iter=get_buffer()->end(); + if(iter.backward_char()) { + auto mark=get_buffer()->create_mark(iter); + scroll_to(mark, 0.0, 1.0, 1.0); + get_buffer()->delete_mark(mark); + } + }); + + async_print_dispatcher.connect([this](){ + async_print_strings_mutex.lock(); + if(async_print_strings.size()>0) { + for(auto &string_bold: async_print_strings) + print(string_bold.first, string_bold.second); + async_print_strings.clear(); + } + async_print_strings_mutex.unlock(); + }); + async_print_on_line_dispatcher.connect([this](){ + async_print_on_line_strings_mutex.lock(); + if(async_print_on_line_strings.size()>0) { + for(auto &line_string: async_print_on_line_strings) + print(line_string.first, line_string.second); + async_print_on_line_strings.clear(); + } + async_print_on_line_strings_mutex.unlock(); + }); +} + +int Terminal::execute(const std::string &command, const boost::filesystem::path &path) { + /*std::string cd_path_and_command; + if(path!="") { + //TODO: Windows... + cd_path_and_command="cd \""+path.string()+"\" && "+command; + } + else + cd_path_and_command=command; + + int stdin_fd, stdout_fd, stderr_fd; + auto pid=popen3(cd_path_and_command.c_str(), stdin_fd, stdout_fd, stderr_fd); + + if (pid<=0) { + async_print("Error: Failed to run command: " + command + "\n"); + return -1; + } + else { + std::thread stderr_thread([this, stderr_fd](){ + char buffer[1024]; + ssize_t n; + while ((n=read(stderr_fd, buffer, 1024)) > 0) { + std::string message; + for(ssize_t c=0;c 0) { + std::string message; + for(ssize_t c=0;c callback) { + /*std::thread async_execute_thread([this, command, path, callback](){ + std::string cd_path_and_command; + if(path!="") { + + //TODO: Windows... + cd_path_and_command="cd \""+path.string()+"\" && "+command; + } + else + cd_path_and_command=command; + + int stdin_fd, stdout_fd, stderr_fd; + async_executes_mutex.lock(); + stdin_buffer.clear(); + auto pid=popen3(cd_path_and_command.c_str(), stdin_fd, stdout_fd, stderr_fd); + async_executes.emplace_back(pid, stdin_fd); + async_executes_mutex.unlock(); + + if (pid<=0) { + async_print("Error: Failed to run command: " + command + "\n"); + if(callback) + callback(-1); + } + else { + std::thread stderr_thread([this, stderr_fd](){ + char buffer[1024]; + ssize_t n; + while ((n=read(stderr_fd, buffer, 1024)) > 0) { + std::string message; + for(ssize_t c=0;c 0) { + std::string message; + for(ssize_t c=0;cfirst==pid) { + async_executes.erase(it); + break; + } + } + stdin_buffer.clear(); + close(stdin_fd); + close(stdout_fd); + close(stderr_fd); + async_executes_mutex.unlock(); + + if(callback) + callback(exit_code); + } + }); + async_execute_thread.detach();*/ + if(callback) + callback(-1); +} + +void Terminal::kill_last_async_execute(bool force) { + async_executes_mutex.lock(); + /*if(async_executes.size()>0) { + if(force) + kill(-async_executes.back().first, SIGTERM); + else + kill(-async_executes.back().first, SIGINT); + }*/ + async_executes_mutex.unlock(); +} + +void Terminal::kill_async_executes(bool force) { + async_executes_mutex.lock(); + /*for(auto &async_execute: async_executes) { + if(force) + kill(-async_execute.first, SIGTERM); + else + kill(-async_execute.first, SIGINT); + }*/ + async_executes_mutex.unlock(); +} + +int Terminal::print(const std::string &message, bool bold){ + INFO("Terminal: PrintMessage"); + if(bold) + get_buffer()->insert_with_tag(get_buffer()->end(), message, bold_tag); + else + get_buffer()->insert(get_buffer()->end(), message); + + auto iter=get_buffer()->end(); + if(iter.backward_char()) { + auto mark=get_buffer()->create_mark(iter); + scroll_to(mark, 0.0, 1.0, 1.0); + get_buffer()->delete_mark(mark); + } + + return get_buffer()->end().get_line(); +} + +void Terminal::print(int line_nr, const std::string &message){ + INFO("Terminal: PrintMessage at line " << line_nr); + auto iter=get_buffer()->get_iter_at_line(line_nr); + while(!iter.ends_line()) + iter++; + get_buffer()->insert(iter, message); +} + +std::shared_ptr Terminal::print_in_progress(std::string start_msg) { + std::shared_ptr in_progress=std::shared_ptr(new Terminal::InProgress(start_msg)); + return in_progress; +} + +void Terminal::async_print(const std::string &message, bool bold) { + async_print_strings_mutex.lock(); + bool dispatch=true; + if(async_print_strings.size()>0) + dispatch=false; + async_print_strings.emplace_back(message, bold); + async_print_strings_mutex.unlock(); + if(dispatch) + async_print_dispatcher(); +} + +void Terminal::async_print(int line_nr, const std::string &message) { + async_print_on_line_strings_mutex.lock(); + bool dispatch=true; + if(async_print_on_line_strings.size()>0) + dispatch=false; + async_print_on_line_strings.emplace_back(line_nr, message); + async_print_on_line_strings_mutex.unlock(); + if(dispatch) + async_print_on_line_dispatcher(); +} + +bool Terminal::on_key_press_event(GdkEventKey *event) { + async_executes_mutex.lock(); + if(async_executes.size()>0) { + get_buffer()->place_cursor(get_buffer()->end()); + auto unicode=gdk_keyval_to_unicode(event->keyval); + char chr=(char)unicode; + if(unicode>=32 && unicode<=126) { + stdin_buffer+=chr; + get_buffer()->insert_at_cursor(stdin_buffer.substr(stdin_buffer.size()-1)); + scroll_to(get_buffer()->get_insert()); + } + else if(event->keyval==GDK_KEY_BackSpace) { + if(stdin_buffer.size()>0 && get_buffer()->get_char_count()>0) { + auto iter=get_buffer()->end(); + iter--; + stdin_buffer.pop_back(); + get_buffer()->erase(iter, get_buffer()->end()); + scroll_to(get_buffer()->get_insert()); + } + } + else if(event->keyval==GDK_KEY_Return) { + stdin_buffer+='\n'; + write(async_executes.back().second, stdin_buffer.c_str(), stdin_buffer.size()); + get_buffer()->insert_at_cursor(stdin_buffer.substr(stdin_buffer.size()-1)); + scroll_to(get_buffer()->get_insert()); + stdin_buffer.clear(); + } + } + async_executes_mutex.unlock(); + return true; +} From fac0d3ff2acb1525acb41948672fc432fb7e144c Mon Sep 17 00:00:00 2001 From: Ole Christian Eidheim Date: Tue, 25 Aug 2015 13:24:46 +0200 Subject: [PATCH 22/54] Update install.md --- docs/install.md | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/docs/install.md b/docs/install.md index 7c2c456..7f92809 100644 --- a/docs/install.md +++ b/docs/install.md @@ -28,10 +28,41 @@ make install ``` ##Windows with MSYS2 (https://msys2.github.io/) -Will be available when the following TODOs are resolved: +Please wait until the following TODOs are resolved: * Newlines are saved properly -* Windows implementation of fork/pipe/read/write +* Windows implementation of creating processes * libclang(mm) finds header-files +* fix make install, and install to mingw[32/64]/bin + +Install dependencies(replace [arch] with i686 or x86_64 depending on your MSYS2 install): +```sh +pacman -S patch autoconf automake-wrapper mingw-w64-[arch]-gtkmm3 mingw-w64-[arch]-boost +``` + +Get juCi++ source: +```sh +git clone https://github.com/cppit/jucipp.git +cd jucipp +``` + +Compiling and installing gtksourceview3 and gtksourceviewmm3: +```sh +cd MINGW-packages/mingw-w64-gtksourceview3/ +makepkg-mingw -sLf +pacman -U mingw-w64-[arch]-gtksourceview3-3.12.0-2-any.pkg.tar.xz +cd ../mingw-w64-gtksourceviewmm3/ +makepkg-mingw -sLf +pacman -U mingw-w64-[arch]-gtksourceviewmm3-3.12.0-1-any.pkg.tar.xz +cd ../../ +``` + +Compile and install juCi++ source: +```sh +cmake -G"MSYS Makefiles" . +make +make install +``` +**You might have to install juci manually** \ No newline at end of file +--> From 218decdb1504b81e216bb6b917c33df89207a1d0 Mon Sep 17 00:00:00 2001 From: Ole Christian Eidheim Date: Tue, 25 Aug 2015 13:39:05 +0200 Subject: [PATCH 23/54] Update install.md --- docs/install.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/install.md b/docs/install.md index 7f92809..2e8837b 100644 --- a/docs/install.md +++ b/docs/install.md @@ -85,7 +85,6 @@ Note that we are currently working on a Windows-version without the need of an X --> ## Run -#### Linux/OS X ```sh juci ``` From 0a4253aa9b326fa1a5a907a171722f3c9d3bab9d Mon Sep 17 00:00:00 2001 From: "U-olece-PC\\olece" Date: Wed, 26 Aug 2015 11:47:34 +0200 Subject: [PATCH 24/54] Terminal now works in Windows. Cmake, make and run works as well. --- src/files.h | 4 + src/terminal.h | 5 +- src/terminal_win.cc | 346 +++++++++++++++++++++++++++++--------------- 3 files changed, 235 insertions(+), 120 deletions(-) diff --git a/src/files.h b/src/files.h index a706c2f..a20069d 100644 --- a/src/files.h +++ b/src/files.h @@ -62,7 +62,11 @@ const std::string configjson = " \"force_kill_last_running\": \"Escape\"\n" " },\n" " \"project\": {\n" +#ifdef _WIN32 +" \"cmake_command\": \"cmake -G\\\"MSYS Makefiles\\\"\",\n" +#else " \"cmake_command\": \"cmake\",\n" +#endif " \"make_command\": \"make\"\n" " },\n" " \"directoryfilter\": {\n" diff --git a/src/terminal.h b/src/terminal.h index dfd1f50..173a4de 100644 --- a/src/terminal.h +++ b/src/terminal.h @@ -54,8 +54,11 @@ private: Glib::RefPtr bold_tag; std::mutex async_executes_mutex; +#ifdef _WIN32 + std::list > async_executes; +#else std::list > async_executes; - +#endif std::string stdin_buffer; }; diff --git a/src/terminal_win.cc b/src/terminal_win.cc index b6a7fdb..2a8b2de 100644 --- a/src/terminal_win.cc +++ b/src/terminal_win.cc @@ -3,10 +3,121 @@ #include "logging.h" #include "singletons.h" #include +#include #include //TODO: remove using namespace std; //TODO: remove +#define BUFSIZE 1024 + +HANDLE popen3(const std::string &command, const boost::filesystem::path &path, HANDLE &stdin_h, HANDLE &stdout_h, HANDLE &stderr_h) { + HANDLE g_hChildStd_IN_Rd = NULL; + HANDLE g_hChildStd_IN_Wr = NULL; + HANDLE g_hChildStd_OUT_Rd = NULL; + HANDLE g_hChildStd_OUT_Wr = NULL; + HANDLE g_hChildStd_ERR_Rd = NULL; + HANDLE g_hChildStd_ERR_Wr = NULL; + + SECURITY_ATTRIBUTES saAttr; + + saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); + saAttr.bInheritHandle = TRUE; + saAttr.lpSecurityDescriptor = NULL; + + if (!CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0)) + return NULL; + if(!SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0)) { + CloseHandle(g_hChildStd_IN_Rd); + CloseHandle(g_hChildStd_IN_Wr); + return NULL; + } + if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0)) { + CloseHandle(g_hChildStd_IN_Rd); + CloseHandle(g_hChildStd_IN_Wr); + return NULL; + } + if(!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0)) { + CloseHandle(g_hChildStd_IN_Rd); + CloseHandle(g_hChildStd_IN_Wr); + CloseHandle(g_hChildStd_OUT_Rd); + CloseHandle(g_hChildStd_OUT_Wr); + return NULL; + } + if (!CreatePipe(&g_hChildStd_ERR_Rd, &g_hChildStd_ERR_Wr, &saAttr, 0)) { + CloseHandle(g_hChildStd_IN_Rd); + CloseHandle(g_hChildStd_IN_Wr); + CloseHandle(g_hChildStd_OUT_Rd); + CloseHandle(g_hChildStd_OUT_Wr); + return NULL; + } + if(!SetHandleInformation(g_hChildStd_ERR_Rd, HANDLE_FLAG_INHERIT, 0)) { + CloseHandle(g_hChildStd_IN_Rd); + CloseHandle(g_hChildStd_IN_Wr); + CloseHandle(g_hChildStd_OUT_Rd); + CloseHandle(g_hChildStd_OUT_Wr); + CloseHandle(g_hChildStd_ERR_Rd); + CloseHandle(g_hChildStd_ERR_Wr); + return NULL; + } + + PROCESS_INFORMATION process_info; + STARTUPINFO siStartInfo; + + ZeroMemory(&process_info, sizeof(PROCESS_INFORMATION)); + + ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); + siStartInfo.cb = sizeof(STARTUPINFO); + siStartInfo.hStdError = g_hChildStd_ERR_Wr; + siStartInfo.hStdOutput = g_hChildStd_OUT_Wr; + siStartInfo.hStdInput = g_hChildStd_IN_Rd; + siStartInfo.dwFlags |= STARTF_USESTDHANDLES; + + char* path_ptr; + if(path=="") + path_ptr=NULL; + else { + auto path_str=path.string(); + path_ptr=new char[path_str.size()+1]; + std::strcpy(path_ptr, path_str.c_str()); + } + char* command_cstr=new char[command.size()+1]; + std::strcpy(command_cstr, command.c_str()); + BOOL bSuccess = CreateProcess(NULL, + command_cstr, // command line + NULL, // process security attributes + NULL, // primary thread security attributes + TRUE, // handles are inherited + 0, // creation flags + NULL, // use parent's environment + path_ptr, // use parent's current directory + &siStartInfo, // STARTUPINFO pointer + &process_info); // receives PROCESS_INFORMATION + + if(!bSuccess) { + CloseHandle(process_info.hProcess); + CloseHandle(process_info.hThread); + CloseHandle(g_hChildStd_IN_Rd); + CloseHandle(g_hChildStd_OUT_Wr); + CloseHandle(g_hChildStd_ERR_Wr); + return NULL; + } + else { + // Close handles to the child process and its primary thread. + // Some applications might keep these handles to monitor the status + // of the child process, for example. + + CloseHandle(process_info.hThread); + CloseHandle(g_hChildStd_IN_Rd); + CloseHandle(g_hChildStd_OUT_Wr); + CloseHandle(g_hChildStd_ERR_Wr); + } + + stdin_h=g_hChildStd_IN_Wr; + stdout_h=g_hChildStd_OUT_Rd; + stderr_h=g_hChildStd_ERR_Rd; + return process_info.hProcess; +} + Terminal::InProgress::InProgress(const std::string& start_msg): stop(false) { waiting_print.connect([this](){ Singleton::terminal()->async_print(line_nr-1, "."); @@ -80,149 +191,144 @@ Terminal::Terminal() { }); } +//Based on the example at https://msdn.microsoft.com/en-us/library/windows/desktop/ms682499(v=vs.85).aspx int Terminal::execute(const std::string &command, const boost::filesystem::path &path) { - /*std::string cd_path_and_command; - if(path!="") { - //TODO: Windows... - cd_path_and_command="cd \""+path.string()+"\" && "+command; - } - else - cd_path_and_command=command; - - int stdin_fd, stdout_fd, stderr_fd; - auto pid=popen3(cd_path_and_command.c_str(), stdin_fd, stdout_fd, stderr_fd); - - if (pid<=0) { + HANDLE stdin_h, stdout_h, stderr_h; + + auto process=popen3(command, path, stdin_h, stdout_h, stderr_h); + if(process==NULL) { async_print("Error: Failed to run command: " + command + "\n"); return -1; } - else { - std::thread stderr_thread([this, stderr_fd](){ - char buffer[1024]; - ssize_t n; - while ((n=read(stderr_fd, buffer, 1024)) > 0) { - std::string message; - for(ssize_t c=0;c callback) { + std::thread async_execute_thread([this, command, path, callback](){ + HANDLE stdin_h, stdout_h, stderr_h; + + async_executes_mutex.lock(); + stdin_buffer.clear(); + auto process=popen3(command, path, stdin_h, stdout_h, stderr_h); + if(process==NULL) { + async_executes_mutex.unlock(); + async_print("Error: Failed to run command: " + command + "\n"); + if(callback) + callback(-1); + return; + } + async_executes.emplace_back(process, stdin_h); + async_executes_mutex.unlock(); + + std::thread stderr_thread([this, stderr_h](){ + DWORD n; + CHAR buffer[BUFSIZE]; + for (;;) { + BOOL bSuccess = ReadFile(stderr_h, buffer, BUFSIZE, &n, NULL); + if(!bSuccess || n == 0) + break; + + std::string message; + for(DWORD c=0;c 0) { - std::string message; - for(ssize_t c=0;c callback) { - /*std::thread async_execute_thread([this, command, path, callback](){ - std::string cd_path_and_command; - if(path!="") { - - //TODO: Windows... - cd_path_and_command="cd \""+path.string()+"\" && "+command; - } - else - cd_path_and_command=command; - - int stdin_fd, stdout_fd, stderr_fd; + unsigned long exit_code; + WaitForSingleObject(process, INFINITE); + GetExitCodeProcess(process, &exit_code); + async_executes_mutex.lock(); + for(auto it=async_executes.begin();it!=async_executes.end();it++) { + if(it->first==process) { + async_executes.erase(it); + break; + } + } stdin_buffer.clear(); - auto pid=popen3(cd_path_and_command.c_str(), stdin_fd, stdout_fd, stderr_fd); - async_executes.emplace_back(pid, stdin_fd); + CloseHandle(process); + CloseHandle(stdin_h); + CloseHandle(stdout_h); + CloseHandle(stderr_h); async_executes_mutex.unlock(); - - if (pid<=0) { - async_print("Error: Failed to run command: " + command + "\n"); - if(callback) - callback(-1); - } - else { - std::thread stderr_thread([this, stderr_fd](){ - char buffer[1024]; - ssize_t n; - while ((n=read(stderr_fd, buffer, 1024)) > 0) { - std::string message; - for(ssize_t c=0;c 0) { - std::string message; - for(ssize_t c=0;cfirst==pid) { - async_executes.erase(it); - break; - } - } - stdin_buffer.clear(); - close(stdin_fd); - close(stdout_fd); - close(stderr_fd); - async_executes_mutex.unlock(); - - if(callback) - callback(exit_code); - } + if(callback) + callback(exit_code); }); - async_execute_thread.detach();*/ - if(callback) - callback(-1); + async_execute_thread.detach(); } void Terminal::kill_last_async_execute(bool force) { async_executes_mutex.lock(); - /*if(async_executes.size()>0) { - if(force) - kill(-async_executes.back().first, SIGTERM); - else - kill(-async_executes.back().first, SIGINT); - }*/ + if(async_executes.size()>0) { + TerminateProcess(async_executes.back().first, 2); + } async_executes_mutex.unlock(); } void Terminal::kill_async_executes(bool force) { async_executes_mutex.lock(); - /*for(auto &async_execute: async_executes) { - if(force) - kill(-async_execute.first, SIGTERM); - else - kill(-async_execute.first, SIGINT); - }*/ + for(auto &async_execute: async_executes) { + TerminateProcess(async_execute.first, 2); + } async_executes_mutex.unlock(); } @@ -300,7 +406,9 @@ bool Terminal::on_key_press_event(GdkEventKey *event) { } else if(event->keyval==GDK_KEY_Return) { stdin_buffer+='\n'; - write(async_executes.back().second, stdin_buffer.c_str(), stdin_buffer.size()); + DWORD written; + WriteFile(async_executes.back().second, stdin_buffer.c_str(), stdin_buffer.size(), &written, NULL); + //TODO: is this line needed? get_buffer()->insert_at_cursor(stdin_buffer.substr(stdin_buffer.size()-1)); scroll_to(get_buffer()->get_insert()); stdin_buffer.clear(); From f9671f5b6e354c977c09a300f8c71fdaaea14308 Mon Sep 17 00:00:00 2001 From: "U-olece-PC\\olece" Date: Wed, 26 Aug 2015 14:31:50 +0200 Subject: [PATCH 25/54] Added true monospace font for Windows. --- src/files.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/files.h b/src/files.h index a20069d..7b390a1 100644 --- a/src/files.h +++ b/src/files.h @@ -10,8 +10,12 @@ const std::string configjson = #ifdef __APPLE__ " \"font\": \"Menlo 11\", " #else +#ifdef _WIN32 +" \"font\": \"Consolas\", " +#else " \"font\": \"Monospace\", " #endif +#endif "//Use \"\" for default font, and for instance \"Monospace 12\" to also set size.\n" " \"clang_types\": {\n" " \"8\": \"def:function\",\n" From c43d579f5adc7bd02d6491f0941535faac0238c2 Mon Sep 17 00:00:00 2001 From: "U-olece-PC\\olece" Date: Thu, 27 Aug 2015 10:05:46 +0200 Subject: [PATCH 26/54] Now will not add carriage returns unless gtk so decides (depending on file I guess), and fixed include problems for MSYS2's buggy libclang install. Mind the latter is a termporary fix. --- src/cmake.cc | 19 ++++++++++++++++++- src/source.cc | 33 +++++++++++++++++++++++++++++++++ src/sourcefile.cc | 2 +- 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/src/cmake.cc b/src/cmake.cc index aab2338..521eefa 100644 --- a/src/cmake.cc +++ b/src/cmake.cc @@ -47,8 +47,25 @@ CMake::CMake(const boost::filesystem::path &path) { bool CMake::create_compile_commands(const boost::filesystem::path &path) { Singleton::terminal()->print("Creating "+path.string()+"/compile_commands.json\n"); //TODO: Windows... - if(Singleton::terminal()->execute(Singleton::Config::terminal()->cmake_command+" . -DCMAKE_EXPORT_COMPILE_COMMANDS=ON", path)==EXIT_SUCCESS) + if(Singleton::terminal()->execute(Singleton::Config::terminal()->cmake_command+" . -DCMAKE_EXPORT_COMPILE_COMMANDS=ON", path)==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=juci::filesystem::read(compile_commands_path); + size_t pos=0; + while((pos=compile_commands_file.find("-I/", pos))!=std::string::npos) { + if(pos+3 Source::ClangViewParse::get_compilation_commands() { } if(file_path.extension()==".h") //TODO: temporary fix for .h-files (parse as c++) arguments.emplace_back("-xc++"); +#ifdef _WIN32 //Temporary fix to MSYS2's libclang + arguments.emplace_back("-IC:/msys32/mingw32/lib/gcc/i686-w64-mingw32/5.2.0/include"); + arguments.emplace_back("-IC:/msys32/mingw32//include"); + arguments.emplace_back("-IC:/msys32/mingw32/lib/gcc/i686-w64-mingw32/5.2.0/include-fixed"); + arguments.emplace_back("-IC:/msys32/mingw32/i686-w64-mingw32/include"); + arguments.emplace_back("-IC:/msys32/mingw32/include/c++/5.2.0"); + arguments.emplace_back("-IC:/msys32/mingw32/include/c++/5.2.0/i686-w64-mingw32"); + arguments.emplace_back("-IC:/msys32/mingw32/include/c++/5.2.0/backward"); + + arguments.emplace_back("-IC:/msys32/mingw64/lib/gcc/i686-w64-mingw32/5.2.0/include"); + arguments.emplace_back("-IC:/msys32/mingw64//include"); + arguments.emplace_back("-IC:/msys32/mingw64/lib/gcc/i686-w64-mingw32/5.2.0/include-fixed"); + arguments.emplace_back("-IC:/msys32/mingw64/i686-w64-mingw32/include"); + arguments.emplace_back("-IC:/msys32/mingw64/include/c++/5.2.0"); + arguments.emplace_back("-IC:/msys32/mingw64/include/c++/5.2.0/i686-w64-mingw32"); + arguments.emplace_back("-IC:/msys32/mingw64/include/c++/5.2.0/backward"); + + arguments.emplace_back("-IC:/msys64/mingw32/lib/gcc/i686-w64-mingw32/5.2.0/include"); + arguments.emplace_back("-IC:/msys64/mingw32//include"); + arguments.emplace_back("-IC:/msys64/mingw32/lib/gcc/i686-w64-mingw32/5.2.0/include-fixed"); + arguments.emplace_back("-IC:/msys64/mingw32/i686-w64-mingw32/include"); + arguments.emplace_back("-IC:/msys64/mingw32/include/c++/5.2.0"); + arguments.emplace_back("-IC:/msys64/mingw32/include/c++/5.2.0/i686-w64-mingw32"); + arguments.emplace_back("-IC:/msys64/mingw32/include/c++/5.2.0/backward"); + + arguments.emplace_back("-IC:/msys64/mingw64/lib/gcc/i686-w64-mingw32/5.2.0/include"); + arguments.emplace_back("-IC:/msys64/mingw64//include"); + arguments.emplace_back("-IC:/msys64/mingw64/lib/gcc/i686-w64-mingw32/5.2.0/include-fixed"); + arguments.emplace_back("-IC:/msys64/mingw64/i686-w64-mingw32/include"); + arguments.emplace_back("-IC:/msys64/mingw64/include/c++/5.2.0"); + arguments.emplace_back("-IC:/msys64/mingw64/include/c++/5.2.0/i686-w64-mingw32"); + arguments.emplace_back("-IC:/msys64/mingw64/include/c++/5.2.0/backward"); +#endif return arguments; } diff --git a/src/sourcefile.cc b/src/sourcefile.cc index ae5780b..6039136 100644 --- a/src/sourcefile.cc +++ b/src/sourcefile.cc @@ -58,7 +58,7 @@ bool juci::filesystem::write(const std::string &path, const std::string &new_con } bool juci::filesystem::write(const std::string &path, Glib::RefPtr buffer) { - std::ofstream output(path); + std::ofstream output(path, std::ofstream::binary); if(output) { auto start_iter=buffer->begin(); auto end_iter=start_iter; From 237381a251926612e1b9506bbf18df121d90dd39 Mon Sep 17 00:00:00 2001 From: "U-olece-PC\\olece" Date: Thu, 27 Aug 2015 10:19:07 +0200 Subject: [PATCH 27/54] Added std::ofstream::binary to all file reads and writes. --- src/sourcefile.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sourcefile.cc b/src/sourcefile.cc index 6039136..7fc796b 100644 --- a/src/sourcefile.cc +++ b/src/sourcefile.cc @@ -7,7 +7,7 @@ const size_t buffer_size=131072; //Only use on small files std::string juci::filesystem::read(const std::string &path) { std::stringstream ss; - std::ifstream input(path); + std::ifstream input(path, std::ofstream::binary); if(input) { ss << input.rdbuf(); input.close(); @@ -16,7 +16,7 @@ std::string juci::filesystem::read(const std::string &path) { } bool juci::filesystem::read(const std::string &path, Glib::RefPtr text_buffer) { - std::ifstream input(path); + std::ifstream input(path, std::ofstream::binary); if(input) { std::vector buffer(buffer_size); size_t read_length; @@ -38,7 +38,7 @@ bool juci::filesystem::read(const std::string &path, Glib::RefPtr juci::filesystem::read_lines(const std::string &path) { std::vector res; - std::ifstream input(path); + std::ifstream input(path, std::ofstream::binary); if (input) { do { res.emplace_back(); } while(getline(input, res.back())); } @@ -48,7 +48,7 @@ std::vector juci::filesystem::read_lines(const std::string &path) { //Only use on small files bool juci::filesystem::write(const std::string &path, const std::string &new_content) { - std::ofstream output(path); + std::ofstream output(path, std::ofstream::binary); if(output) output << new_content; else From 52adf1c07d6d35aaab91649b9ce2b927690e28d7 Mon Sep 17 00:00:00 2001 From: Ole Christian Eidheim Date: Thu, 27 Aug 2015 12:32:32 +0200 Subject: [PATCH 28/54] Now doing a soft reparse every time a clangview-page gets focused (in case a header file for instance is changed) --- src/source.h | 2 +- src/window.cc | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/source.h b/src/source.h index e51ff3d..f71d3ee 100644 --- a/src/source.h +++ b/src/source.h @@ -102,9 +102,9 @@ namespace Source { public: ClangViewParse(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path); boost::filesystem::path project_path; + void start_reparse(); protected: void init_parse(); - void start_reparse(); bool on_key_press_event(GdkEventKey* key); bool on_focus_out_event(GdkEventFocus* event); std::unique_ptr clang_tu; diff --git a/src/window.cc b/src/window.cc index bba2e52..75c528a 100644 --- a/src/window.cc +++ b/src/window.cc @@ -93,6 +93,9 @@ Window::Window() : box(Gtk::ORIENTATION_VERTICAL), notebook(directories), compil directories.select(notebook.get_current_view()->file_path); + if(auto source_view=dynamic_cast(notebook.get_current_view())) + source_view->start_reparse(); + Singleton::status()->set_text(notebook.get_current_view()->status); } }); From 729b8af35cbee50fbe851956533aafa54b2ed9d0 Mon Sep 17 00:00:00 2001 From: Ole Christian Eidheim Date: Thu, 27 Aug 2015 13:09:49 +0200 Subject: [PATCH 29/54] Fixed: assertion 'buffer->priv->user_action_count > 0' failed --- src/selectiondialog.cc | 4 +++- src/selectiondialog.h | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/selectiondialog.cc b/src/selectiondialog.cc index 9965b98..8b73072 100644 --- a/src/selectiondialog.cc +++ b/src/selectiondialog.cc @@ -64,6 +64,7 @@ void SelectionDialogBase::add_row(const std::string& row, const std::string& too } void SelectionDialogBase::show() { + shown=true; move(); window->show_all(); } @@ -72,8 +73,9 @@ void SelectionDialogBase::hide() { window->hide(); if(tooltips) tooltips->hide(); - if(on_hide) + if(on_hide && shown) on_hide(); + shown=false; } void SelectionDialogBase::update_tooltips() { diff --git a/src/selectiondialog.h b/src/selectiondialog.h index abdd59b..e454a3c 100644 --- a/src/selectiondialog.h +++ b/src/selectiondialog.h @@ -31,6 +31,8 @@ protected: std::unique_ptr tooltips; std::unordered_map tooltip_texts; std::string last_row; +private: + bool shown=false; }; class SelectionDialog : public SelectionDialogBase { From 1fc5a53f70166d163e51a938a8388607f404605f Mon Sep 17 00:00:00 2001 From: Ole Christian Eidheim Date: Thu, 27 Aug 2015 13:17:27 +0200 Subject: [PATCH 30/54] Fixed bug where autocomplete could not finish if a variable in a class was defined later in the source code. --- src/source.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/source.cc b/src/source.cc index 43268c0..3a12d4c 100644 --- a/src/source.cc +++ b/src/source.cc @@ -1194,7 +1194,7 @@ void Source::ClangViewAutocomplete::autocomplete() { std::shared_ptr > buffer_map=std::make_shared >(); auto& buffer=(*buffer_map)[this->file_path.string()]; - buffer=get_buffer()->get_text(get_buffer()->begin(), get_buffer()->get_insert()->get_iter()); + buffer=get_buffer()->get_text(); auto iter = get_source_buffer()->get_insert()->get_iter(); auto line_nr=iter.get_line()+1; auto column_nr=iter.get_line_offset()+1; From 96d9330d9dbc77e6460ba5b4004759f6e015b59a Mon Sep 17 00:00:00 2001 From: Ole Christian Eidheim Date: Thu, 27 Aug 2015 13:53:37 +0200 Subject: [PATCH 31/54] Added slight delay on tag-similar-tokens so that scrolling up/down with arrowkeys is more smooth. --- src/source.cc | 8 ++++++-- src/source.h | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/source.cc b/src/source.cc index 3a12d4c..6f652f5 100644 --- a/src/source.cc +++ b/src/source.cc @@ -1340,8 +1340,12 @@ Source::ClangViewAutocomplete(file_path, project_path) { get_buffer()->signal_mark_set().connect([this](const Gtk::TextBuffer::iterator& iterator, const Glib::RefPtr& mark){ if(mark->get_name()=="insert") { - auto usr=get_token(); - tag_similar_tokens(usr); + delayed_tag_similar_tokens_connection.disconnect(); + delayed_tag_similar_tokens_connection=Glib::signal_timeout().connect([this]() { + auto usr=get_token(); + tag_similar_tokens(usr); + return false; + }, 100); } }); diff --git a/src/source.h b/src/source.h index f71d3ee..5380f00 100644 --- a/src/source.h +++ b/src/source.h @@ -177,6 +177,7 @@ namespace Source { private: Glib::RefPtr similar_tokens_tag; std::string last_similar_tokens_tagged; + sigc::connection delayed_tag_similar_tokens_connection; std::unique_ptr selection_dialog; bool renaming=false; }; From 7213702d3f400ecd376865146fa87230c1693d53 Mon Sep 17 00:00:00 2001 From: Ole Christian Eidheim Date: Thu, 27 Aug 2015 14:22:02 +0200 Subject: [PATCH 32/54] Fixed potential crash if file-read accidently splits up an UTF-8 char. --- src/sourcefile.cc | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/sourcefile.cc b/src/sourcefile.cc index 7fc796b..260a5fb 100644 --- a/src/sourcefile.cc +++ b/src/sourcefile.cc @@ -20,13 +20,18 @@ bool juci::filesystem::read(const std::string &path, Glib::RefPtr buffer(buffer_size); size_t read_length; + std::string buffer_str; while((read_length=input.read(&buffer[0], buffer_size).gcount())>0) { - auto ustr=Glib::ustring(std::string(&buffer[0], read_length)); - if(ustr.validate()) - text_buffer->insert_at_cursor(ustr); - else { - input.close(); - return false; + buffer_str+=std::string(&buffer[0], read_length); + if(buffer_str.back()>=0) { + auto ustr=Glib::ustring(buffer_str); + buffer_str=""; + if(ustr.validate()) + text_buffer->insert_at_cursor(ustr); + else { + input.close(); + return false; + } } } input.close(); From 25ef8f8610774975bd8947bb3a159a668698bea1 Mon Sep 17 00:00:00 2001 From: eidheim Date: Thu, 27 Aug 2015 16:02:03 +0200 Subject: [PATCH 33/54] Getting ready to add spellcheck in comments using aspell library. --- src/notebook.cc | 2 +- src/source.cc | 20 +++++++++++++++++++- src/source.h | 2 +- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/notebook.cc b/src/notebook.cc index 7bfd4f9..ad329ab 100644 --- a/src/notebook.cc +++ b/src/notebook.cc @@ -67,7 +67,7 @@ void Notebook::open(const boost::filesystem::path &file_path) { else Singleton::terminal()->print("Error: could not find project path for "+file_path.string()+"\n"); } - source_views.emplace_back(new Source::ClangView(file_path, project_path)); + source_views.emplace_back(new Source::ClangView(file_path, project_path, language)); } else source_views.emplace_back(new Source::GenericView(file_path, language)); diff --git a/src/source.cc b/src/source.cc index 6f652f5..adab60d 100644 --- a/src/source.cc +++ b/src/source.cc @@ -97,6 +97,19 @@ Source::View::View(const boost::filesystem::path &file_path): file_path(file_pat tab+=tab_char; tabs_regex=std::regex(std::string("^(")+tab_char+"*)(.*)$"); + + get_buffer()->signal_changed().connect([this](){ + auto iter=get_buffer()->get_insert()->get_iter(); + if(iter.backward_char()) { + auto context_iter=iter; + if(context_iter.backward_char()) { + if(get_source_buffer()->iter_has_context_class(context_iter, "comment")) { + //TODO: get word, and spellcheck + //cout << "comment: " << (char)*iter << endl; + } + } + } + }); } void Source::View::search_occurrences_updated(GtkWidget* widget, GParamSpec* property, gpointer data) { @@ -1394,7 +1407,12 @@ Source::ClangViewAutocomplete(file_path, project_path) { }; } -Source::ClangView::ClangView(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path): ClangViewRefactor(file_path, project_path) { +Source::ClangView::ClangView(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path, Glib::RefPtr language): ClangViewRefactor(file_path, project_path) { + if(language) { + get_source_buffer()->set_highlight_syntax(false); + get_source_buffer()->set_language(language); + } + do_delete_object.connect([this](){ if(delete_thread.joinable()) delete_thread.join(); diff --git a/src/source.h b/src/source.h index 5380f00..20185f9 100644 --- a/src/source.h +++ b/src/source.h @@ -184,7 +184,7 @@ namespace Source { class ClangView : public ClangViewRefactor { public: - ClangView(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path); + ClangView(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path, Glib::RefPtr language); void async_delete(); bool restart_parse(); private: From 946134d7fe2e68fd9afc11abdcb4d2c9ffacb875 Mon Sep 17 00:00:00 2001 From: eidheim Date: Thu, 27 Aug 2015 18:28:11 +0200 Subject: [PATCH 34/54] Fixed autocomplete again, now should work in all cases. --- src/source.cc | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/source.cc b/src/source.cc index adab60d..202b17e 100644 --- a/src/source.cc +++ b/src/source.cc @@ -1207,15 +1207,23 @@ void Source::ClangViewAutocomplete::autocomplete() { std::shared_ptr > buffer_map=std::make_shared >(); auto& buffer=(*buffer_map)[this->file_path.string()]; - buffer=get_buffer()->get_text(); - auto iter = get_source_buffer()->get_insert()->get_iter(); + auto iter=get_buffer()->get_insert()->get_iter(); + buffer=get_buffer()->get_text(get_buffer()->begin(), iter); auto line_nr=iter.get_line()+1; auto column_nr=iter.get_line_offset()+1; - while((buffer.back()>='a' && buffer.back()<='z') || (buffer.back()>='A' && buffer.back()<='Z') || (buffer.back()>='0' && buffer.back()<='9') || buffer.back()=='_') { - buffer.pop_back(); - column_nr--; + unsigned c=1; + if(c<=buffer.size()) { + char *chr=&buffer[buffer.size()-c]; + while((*chr>='a' && *chr<='z') || (*chr>='A' && *chr<='Z') || (*chr>='0' && *chr<='9') || *chr=='_') { + *chr=' '; + column_nr--; + c++; + if(c>buffer.size()) + break; + chr--; + } } - buffer+="\n"; + buffer+=get_buffer()->get_text(iter, get_buffer()->end()); set_status("autocomplete..."); if(autocomplete_thread.joinable()) autocomplete_thread.join(); From bc6785fcee3a0da64e2dfb92841de3c75f2d12d9 Mon Sep 17 00:00:00 2001 From: eidheim Date: Fri, 28 Aug 2015 08:10:23 +0200 Subject: [PATCH 35/54] Some cleanup. --- src/cmake.cc | 1 - src/terminal.cc | 98 ++++++++++++++++++++++----------------------- src/terminal_win.cc | 17 ++++---- src/window.cc | 3 -- 4 files changed, 57 insertions(+), 62 deletions(-) diff --git a/src/cmake.cc b/src/cmake.cc index 521eefa..d112a26 100644 --- a/src/cmake.cc +++ b/src/cmake.cc @@ -46,7 +46,6 @@ CMake::CMake(const boost::filesystem::path &path) { bool CMake::create_compile_commands(const boost::filesystem::path &path) { Singleton::terminal()->print("Creating "+path.string()+"/compile_commands.json\n"); - //TODO: Windows... if(Singleton::terminal()->execute(Singleton::Config::terminal()->cmake_command+" . -DCMAKE_EXPORT_COMPILE_COMMANDS=ON", path)==EXIT_SUCCESS) { #ifdef _WIN32 //Temporary fix to MSYS2's libclang auto compile_commands_path=path; diff --git a/src/terminal.cc b/src/terminal.cc index 4df8e24..aed5906 100644 --- a/src/terminal.cc +++ b/src/terminal.cc @@ -8,57 +8,74 @@ #include //TODO: remove using namespace std; //TODO: remove -//TODO: Windows... //A working implementation of popen3, with all pipes getting closed properly. //TODO: Eidheim is going to publish this one on his github, along with example uses -pid_t popen3(const char *command, int &stdin_fd, int &stdout_fd, int &stderr_fd) { +pid_t popen3(const std::string &command, const std::string &path, int *stdin_fd, int *stdout_fd, int *stderr_fd) { pid_t pid; - int p_stdin[2], p_stdout[2], p_stderr[2]; + int stdin_p[2], stdout_p[2], stderr_p[2]; - if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0 || pipe(p_stderr) != 0) { - close(p_stdin[0]); - close(p_stdout[0]); - close(p_stderr[0]); - close(p_stdin[1]); - close(p_stdout[1]); - close(p_stderr[1]); + if(stdin_fd!=nullptr && pipe(stdin_p)!=0) { + close(stdin_p[0]); + close(stdin_p[1]); return -1; } - + if(stdout_fd!=nullptr && pipe(stdout_p)!=0) { + if(stdin_fd!=nullptr) close(stdin_p[0]); + if(stdin_fd!=nullptr) close(stdin_p[1]); + close(stdout_p[0]); + close(stdout_p[1]); + return -1; + } + if(stderr_fd!=nullptr && pipe(stderr_p)!=0) { + if(stdin_fd!=nullptr) close(stdin_p[0]); + if(stdin_fd!=nullptr) close(stdin_p[1]); + if(stdout_fd!=nullptr) close(stdout_p[0]); + if(stdout_fd!=nullptr) close(stdout_p[1]); + close(stderr_p[0]); + close(stderr_p[1]); + return -1; + } + pid = fork(); if (pid < 0) { - close(p_stdin[0]); - close(p_stdout[0]); - close(p_stderr[0]); - close(p_stdin[1]); - close(p_stdout[1]); - close(p_stderr[1]); + if(stdin_fd!=nullptr) close(stdin_p[0]); + if(stdin_fd!=nullptr) close(stdin_p[1]); + if(stdout_fd!=nullptr) close(stdout_p[0]); + if(stdout_fd!=nullptr) close(stdout_p[1]); + if(stderr_fd!=nullptr) close(stderr_p[0]); + if(stderr_fd!=nullptr) close(stderr_p[1]); return pid; } else if (pid == 0) { - close(p_stdin[1]); - close(p_stdout[0]); - close(p_stderr[0]); - dup2(p_stdin[0], 0); - dup2(p_stdout[1], 1); - dup2(p_stderr[1], 2); + if(stdin_fd!=nullptr) close(stdin_p[1]); + if(stdout_fd!=nullptr) close(stdout_p[0]); + if(stderr_fd!=nullptr) close(stderr_p[0]); + if(stdin_fd!=nullptr) dup2(stdin_p[0], 0); + if(stdout_fd!=nullptr) dup2(stdout_p[1], 1); + if(stderr_fd!=nullptr) dup2(stderr_p[1], 2); setpgid(0, 0); //TODO: See here on how to emulate tty for colors: http://stackoverflow.com/questions/1401002/trick-an-application-into-thinking-its-stdin-is-interactive-not-a-pipe //TODO: One solution is: echo "command;exit"|script -q /dev/null - execl("/bin/sh", "sh", "-c", command, NULL); + std::string cd_path_and_command; + if(path!="") { + cd_path_and_command="cd \""+path+"\" && "+command; + } + else + cd_path_and_command=command; + execl("/bin/sh", "sh", "-c", cd_path_and_command.c_str(), NULL); perror("execl"); exit(EXIT_FAILURE); } - close(p_stdin[0]); - close(p_stdout[1]); - close(p_stderr[1]); + if(stdin_fd!=nullptr) close(stdin_p[0]); + if(stdout_fd!=nullptr) close(stdout_p[1]); + if(stderr_fd!=nullptr) close(stderr_p[1]); - stdin_fd = p_stdin[1]; - stdout_fd = p_stdout[0]; - stderr_fd = p_stderr[0]; + if(stdin_fd!=nullptr) *stdin_fd = stdin_p[1]; + if(stdout_fd!=nullptr) *stdout_fd = stdout_p[0]; + if(stderr_fd!=nullptr) *stderr_fd = stderr_p[0]; return pid; } @@ -137,16 +154,8 @@ Terminal::Terminal() { } int Terminal::execute(const std::string &command, const boost::filesystem::path &path) { - std::string cd_path_and_command; - if(path!="") { - //TODO: Windows... - cd_path_and_command="cd \""+path.string()+"\" && "+command; - } - else - cd_path_and_command=command; - int stdin_fd, stdout_fd, stderr_fd; - auto pid=popen3(cd_path_and_command.c_str(), stdin_fd, stdout_fd, stderr_fd); + auto pid=popen3(command, path.string(), &stdin_fd, &stdout_fd, &stderr_fd); if (pid<=0) { async_print("Error: Failed to run command: " + command + "\n"); @@ -189,19 +198,10 @@ int Terminal::execute(const std::string &command, const boost::filesystem::path void Terminal::async_execute(const std::string &command, const boost::filesystem::path &path, std::function callback) { std::thread async_execute_thread([this, command, path, callback](){ - std::string cd_path_and_command; - if(path!="") { - - //TODO: Windows... - cd_path_and_command="cd \""+path.string()+"\" && "+command; - } - else - cd_path_and_command=command; - int stdin_fd, stdout_fd, stderr_fd; async_executes_mutex.lock(); stdin_buffer.clear(); - auto pid=popen3(cd_path_and_command.c_str(), stdin_fd, stdout_fd, stderr_fd); + auto pid=popen3(command, path.string(), &stdin_fd, &stdout_fd, &stderr_fd); async_executes.emplace_back(pid, stdin_fd); async_executes_mutex.unlock(); diff --git a/src/terminal_win.cc b/src/terminal_win.cc index 2a8b2de..e79014d 100644 --- a/src/terminal_win.cc +++ b/src/terminal_win.cc @@ -10,7 +10,7 @@ using namespace std; //TODO: remove #define BUFSIZE 1024 -HANDLE popen3(const std::string &command, const boost::filesystem::path &path, HANDLE &stdin_h, HANDLE &stdout_h, HANDLE &stderr_h) { +HANDLE popen3(const std::string &command, const std::string &path, HANDLE *stdin_h, HANDLE *stdout_h, HANDLE *stderr_h) { HANDLE g_hChildStd_IN_Rd = NULL; HANDLE g_hChildStd_IN_Wr = NULL; HANDLE g_hChildStd_OUT_Rd = NULL; @@ -76,9 +76,8 @@ HANDLE popen3(const std::string &command, const boost::filesystem::path &path, H if(path=="") path_ptr=NULL; else { - auto path_str=path.string(); - path_ptr=new char[path_str.size()+1]; - std::strcpy(path_ptr, path_str.c_str()); + path_ptr=new char[path.size()+1]; + std::strcpy(path_ptr, path.c_str()); } char* command_cstr=new char[command.size()+1]; std::strcpy(command_cstr, command.c_str()); @@ -112,9 +111,9 @@ HANDLE popen3(const std::string &command, const boost::filesystem::path &path, H CloseHandle(g_hChildStd_ERR_Wr); } - stdin_h=g_hChildStd_IN_Wr; - stdout_h=g_hChildStd_OUT_Rd; - stderr_h=g_hChildStd_ERR_Rd; + *stdin_h=g_hChildStd_IN_Wr; + *stdout_h=g_hChildStd_OUT_Rd; + *stderr_h=g_hChildStd_ERR_Rd; return process_info.hProcess; } @@ -195,7 +194,7 @@ Terminal::Terminal() { int Terminal::execute(const std::string &command, const boost::filesystem::path &path) { HANDLE stdin_h, stdout_h, stderr_h; - auto process=popen3(command, path, stdin_h, stdout_h, stderr_h); + auto process=popen3(command, path.string(), &stdin_h, &stdout_h, &stderr_h); if(process==NULL) { async_print("Error: Failed to run command: " + command + "\n"); return -1; @@ -249,7 +248,7 @@ void Terminal::async_execute(const std::string &command, const boost::filesystem async_executes_mutex.lock(); stdin_buffer.clear(); - auto process=popen3(command, path, stdin_h, stdout_h, stderr_h); + auto process=popen3(command, path.string(), &stdin_h, &stdout_h, &stderr_h); if(process==NULL) { async_executes_mutex.unlock(); async_print("Error: Failed to run command: " + command + "\n"); diff --git a/src/window.cc b/src/window.cc index 75c528a..b3a7b18 100644 --- a/src/window.cc +++ b/src/window.cc @@ -229,12 +229,10 @@ void Window::create_menu() { if(executable_path!="") { compiling=true; Singleton::terminal()->print("Compiling and running "+executable_path.string()+"\n"); - //TODO: Windows... auto project_path=cmake.project_path; Singleton::terminal()->async_execute(Singleton::Config::terminal()->make_command, cmake.project_path, [this, executable_path, project_path](int exit_code){ compiling=false; if(exit_code==EXIT_SUCCESS) { - //TODO: Windows... auto executable_path_spaces_fixed=executable_path.string(); char last_char=0; for(size_t c=0;cprint("Compiling project "+cmake.project_path.string()+"\n"); - //TODO: Windows... Singleton::terminal()->async_execute(Singleton::Config::terminal()->make_command, cmake.project_path, [this](int exit_code){ compiling=false; }); From 1858cc2311ddf6192c7a800aef9209e720cb7c94 Mon Sep 17 00:00:00 2001 From: eidheim Date: Fri, 28 Aug 2015 09:10:36 +0200 Subject: [PATCH 36/54] Cleanup of autocomplete buffer creation. --- src/source.cc | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/src/source.cc b/src/source.cc index 202b17e..de8146d 100644 --- a/src/source.cc +++ b/src/source.cc @@ -1206,24 +1206,17 @@ void Source::ClangViewAutocomplete::autocomplete() { }); std::shared_ptr > buffer_map=std::make_shared >(); - auto& buffer=(*buffer_map)[this->file_path.string()]; + auto ustr=get_buffer()->get_text(); auto iter=get_buffer()->get_insert()->get_iter(); - buffer=get_buffer()->get_text(get_buffer()->begin(), iter); auto line_nr=iter.get_line()+1; auto column_nr=iter.get_line_offset()+1; - unsigned c=1; - if(c<=buffer.size()) { - char *chr=&buffer[buffer.size()-c]; - while((*chr>='a' && *chr<='z') || (*chr>='A' && *chr<='Z') || (*chr>='0' && *chr<='9') || *chr=='_') { - *chr=' '; - column_nr--; - c++; - if(c>buffer.size()) - break; - chr--; - } + auto pos=iter.get_offset()-1; + while(pos>=0 && ((ustr[pos]>='a' && ustr[pos]<='z') || (ustr[pos]>='A' && ustr[pos]<='Z') || (ustr[pos]>='0' && ustr[pos]<='9') || ustr[pos]=='_')) { + ustr.replace(pos, 1, " "); + column_nr--; + pos--; } - buffer+=get_buffer()->get_text(iter, get_buffer()->end()); + (*buffer_map)[this->file_path.string()]=std::move(ustr); //TODO: does this work? set_status("autocomplete..."); if(autocomplete_thread.joinable()) autocomplete_thread.join(); From d0e77f2397426f5443b11f7641658ba6965dd8e0 Mon Sep 17 00:00:00 2001 From: eidheim Date: Fri, 28 Aug 2015 09:17:21 +0200 Subject: [PATCH 37/54] Now scrolls to the point where undo or redo happens. --- src/window.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/window.cc b/src/window.cc index b3a7b18..eb8585f 100644 --- a/src/window.cc +++ b/src/window.cc @@ -165,6 +165,7 @@ void Window::create_menu() { auto undo_manager = notebook.get_current_view()->get_source_buffer()->get_undo_manager(); if (undo_manager->can_undo()) { undo_manager->undo(); + notebook.get_current_view()->scroll_to(notebook.get_current_view()->get_buffer()->get_insert()); } } INFO("Done undo"); @@ -175,6 +176,7 @@ void Window::create_menu() { auto undo_manager = notebook.get_current_view()->get_source_buffer()->get_undo_manager(); if(undo_manager->can_redo()) { undo_manager->redo(); + notebook.get_current_view()->scroll_to(notebook.get_current_view()->get_buffer()->get_insert()); } } INFO("Done Redo"); From 4eb85d90c6903fb37b3f6bcd69a5b504fce2a504 Mon Sep 17 00:00:00 2001 From: eidheim Date: Fri, 28 Aug 2015 11:35:50 +0200 Subject: [PATCH 38/54] Added spellcheck using aspell to comments and strings. Please install (lib)aspell(-dev) and rm ~/.juci to test. --- docs/install.md | 6 ++-- src/CMakeLists.txt | 6 +++- src/config.cc | 2 ++ src/files.h | 1 + src/source.cc | 76 +++++++++++++++++++++++++++++++++++++++------- src/source.h | 6 ++++ 6 files changed, 82 insertions(+), 15 deletions(-) diff --git a/docs/install.md b/docs/install.md index 2e8837b..12062d5 100644 --- a/docs/install.md +++ b/docs/install.md @@ -4,7 +4,7 @@ Before installation, please install libclangmm, see [installation guide](http:// ## Debian/Ubuntu ```sh -sudo apt-get install pkg-config libboost-system-dev libboost-thread-dev libboost-filesystem-dev libboost-log-dev libgtkmm-3.0-dev libgtksourceviewmm-3.0-dev +sudo apt-get install pkg-config libboost-system-dev libboost-thread-dev libboost-filesystem-dev libboost-log-dev libgtkmm-3.0-dev libgtksourceviewmm-3.0-dev libaspell-dev ``` ```sh git clone http://github.com/cppit/jucipp.git @@ -16,7 +16,7 @@ sudo make install ## OS X with Homebrew (http://brew.sh/) ```sh -brew install pkg-config boost gtkmm3 gtksourceviewmm3 +brew install pkg-config boost gtkmm3 gtksourceviewmm3 aspell ``` ```sh @@ -36,7 +36,7 @@ Please wait until the following TODOs are resolved: Install dependencies(replace [arch] with i686 or x86_64 depending on your MSYS2 install): ```sh -pacman -S patch autoconf automake-wrapper mingw-w64-[arch]-gtkmm3 mingw-w64-[arch]-boost +pacman -S patch autoconf automake-wrapper mingw-w64-[arch]-gtkmm3 mingw-w64-[arch]-boost mingw-w64-[arch]-aspell ``` Get juCi++ source: diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d15e8e1..3dcada4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -56,6 +56,8 @@ validate(${GTKMM_FOUND} "gtkmm" "libgtkmm-dev" "gtkmm") pkg_check_modules(GTKSVMM gtksourceviewmm-3.0) validate(${GTKSVMM_FOUND} "gtksvmm" "libgtksvmm-dev" "gtkmmsv") +find_package(ASPELL REQUIRED) + set(source_files juci.h juci.cc menu.h @@ -105,7 +107,8 @@ if(${validation}) ${GTKMM_INCLUDE_DIRS} ${GTKSVMM_INCLUDE_DIRS} ${LCL_INCLUDE_DIRS} - ${LIBCLANG_INCLUDE_DIRS}) + ${LIBCLANG_INCLUDE_DIRS} + ${ASPELL_INCLUDE_DIR}) link_directories( ${GTKMM_LIBRARY_DIRS} @@ -128,6 +131,7 @@ if(${validation}) ${GTKMM_LIBRARIES} ${GTKSVMM_LIBRARIES} ${Boost_LIBRARIES} + ${ASPELL_LIBRARIES} # ${PYTHON_LIBRARIES} ) diff --git a/src/config.cc b/src/config.cc index 0de059c..7d6da88 100644 --- a/src/config.cc +++ b/src/config.cc @@ -46,6 +46,8 @@ void MainConfig::GenerateSource() { auto source_cfg = Singleton::Config::source(); auto source_json = cfg.get_child("source"); + source_cfg->spellcheck_language = source_json.get("spellcheck_language"); + source_cfg->default_tab_char = source_json.get("default_tab_char"); source_cfg->default_tab_size = source_json.get("default_tab_size"); source_cfg->auto_tab_char_and_size = source_json.get("auto_tab_char_and_size"); diff --git a/src/files.h b/src/files.h index 7b390a1..516cf05 100644 --- a/src/files.h +++ b/src/files.h @@ -17,6 +17,7 @@ const std::string configjson = #endif #endif "//Use \"\" for default font, and for instance \"Monospace 12\" to also set size.\n" +" \"spellcheck_language\": \"en_US\", \n" " \"clang_types\": {\n" " \"8\": \"def:function\",\n" " \"21\": \"def:function\",\n" diff --git a/src/source.cc b/src/source.cc index de8146d..82168b0 100644 --- a/src/source.cc +++ b/src/source.cc @@ -7,14 +7,16 @@ #include "singletons.h" #include #include +#include -#include //TODO: remove using namespace std; //TODO: remove namespace sigc { SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE } +AspellConfig* spellcheck_config=NULL; + Glib::RefPtr Source::guess_language(const boost::filesystem::path &file_path) { auto language_manager=Gsv::LanguageManager::get_default(); bool result_uncertain = false; @@ -98,18 +100,43 @@ Source::View::View(const boost::filesystem::path &file_path): file_path(file_pat tabs_regex=std::regex(std::string("^(")+tab_char+"*)(.*)$"); - get_buffer()->signal_changed().connect([this](){ - auto iter=get_buffer()->get_insert()->get_iter(); - if(iter.backward_char()) { - auto context_iter=iter; - if(context_iter.backward_char()) { - if(get_source_buffer()->iter_has_context_class(context_iter, "comment")) { - //TODO: get word, and spellcheck - //cout << "comment: " << (char)*iter << endl; + if(spellcheck_config==NULL) { + spellcheck_config=new_aspell_config(); + aspell_config_replace(spellcheck_config, "lang", Singleton::Config::source()->spellcheck_language.c_str()); + } + + spellcheck_possible_err=new_aspell_speller(spellcheck_config); + spellcheck_checker=NULL; + if (aspell_error_number(spellcheck_possible_err) != 0) + std::cerr << "Spell check error: " << aspell_error_message(spellcheck_possible_err) << std::endl; + else { + spellcheck_checker = to_aspell_speller(spellcheck_possible_err); + + auto tag=get_buffer()->create_tag("spellcheck_error"); + tag->property_underline()=Pango::Underline::UNDERLINE_ERROR; + + get_buffer()->signal_changed().connect([this](){ + auto iter=get_buffer()->get_insert()->get_iter(); + if(iter.backward_char()) { + auto context_iter=iter; + if(context_iter.backward_char()) { + if(get_source_buffer()->iter_has_context_class(context_iter, "comment") || get_source_buffer()->iter_has_context_class(context_iter, "string")) { + if(*iter==32) { //Might have used space to split two words + auto first=iter; + auto second=iter; + if(first.backward_char() && second.forward_char()) { + get_buffer()->remove_tag_by_name("spellcheck_error", first, second); + spellcheck(first); + spellcheck(second); + } + } + else + spellcheck(iter); + } } } - } - }); + }); + } } void Source::View::search_occurrences_updated(GtkWidget* widget, GParamSpec* property, gpointer data) { @@ -121,6 +148,8 @@ void Source::View::search_occurrences_updated(GtkWidget* widget, GParamSpec* pro Source::View::~View() { g_clear_object(&search_context); g_clear_object(&search_settings); + + delete_aspell_speller(spellcheck_checker); } void Source::View::search_highlight(const std::string &text, bool case_sensitive, bool regex) { @@ -477,6 +506,31 @@ std::pair Source::View::find_tab_char_and_size() { return {found_tab_char, found_tab_size}; } +void Source::View::spellcheck(Gtk::TextIter iter) { + auto start=iter; + auto end=iter; + + while((*iter>=48 && *iter<=57) || (*iter>=65 && *iter<=90) || (*iter>=97 && *iter<=122) || *iter==95 || *iter>=128) { + start=iter; + if(!iter.backward_char()) + break; + } + while((*end>=48 && *end<=57) || (*end>=65 && *end<=90) || (*end>=97 && *end<=122) || *end==95 || *end>=128) { + if(!end.forward_char()) + break; + } + auto word=get_buffer()->get_text(start, end); + std::vector words; + if(word.size()>0) { + auto correct = aspell_speller_check(spellcheck_checker, word.data(), word.bytes()); + if(correct==0) + get_buffer()->apply_tag_by_name("spellcheck_error", start, end); + else + get_buffer()->remove_tag_by_name("spellcheck_error", start, end); + } +} + + ///////////////////// //// GenericView //// ///////////////////// diff --git a/src/source.h b/src/source.h index 20185f9..9a8dd15 100644 --- a/src/source.h +++ b/src/source.h @@ -15,6 +15,7 @@ #include "selectiondialog.h" #include #include +#include namespace Source { Glib::RefPtr guess_language(const boost::filesystem::path &file_path); @@ -23,6 +24,7 @@ namespace Source { public: std::string style; std::string font; + std::string spellcheck_language; bool auto_tab_char_and_size; char default_tab_char; unsigned default_tab_size; @@ -91,6 +93,10 @@ namespace Source { GtkSourceSearchContext *search_context; GtkSourceSearchSettings *search_settings; static void search_occurrences_updated(GtkWidget* widget, GParamSpec* property, gpointer data); + + AspellCanHaveError *spellcheck_possible_err; + AspellSpeller *spellcheck_checker; + void spellcheck(Gtk::TextIter iter); }; // class View class GenericView : public View { From b9e4699cbf9f3e36d65ea4b8706b65c2d97ca387 Mon Sep 17 00:00:00 2001 From: eidheim Date: Fri, 28 Aug 2015 11:52:23 +0200 Subject: [PATCH 39/54] Had to install aspell-en on MSYS2. --- docs/install.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/install.md b/docs/install.md index 12062d5..a5e650d 100644 --- a/docs/install.md +++ b/docs/install.md @@ -36,7 +36,7 @@ Please wait until the following TODOs are resolved: Install dependencies(replace [arch] with i686 or x86_64 depending on your MSYS2 install): ```sh -pacman -S patch autoconf automake-wrapper mingw-w64-[arch]-gtkmm3 mingw-w64-[arch]-boost mingw-w64-[arch]-aspell +pacman -S patch autoconf automake-wrapper mingw-w64-[arch]-gtkmm3 mingw-w64-[arch]-boost mingw-w64-[arch]-aspell mingw-w64-[arch]-aspell-en ``` Get juCi++ source: From 19e5bf5c36144646ee8afe6cf6644911dce290be Mon Sep 17 00:00:00 2001 From: eidheim Date: Fri, 28 Aug 2015 11:56:56 +0200 Subject: [PATCH 40/54] Guess Linux also needs aspell-en. --- docs/install.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/install.md b/docs/install.md index a5e650d..7764368 100644 --- a/docs/install.md +++ b/docs/install.md @@ -4,7 +4,7 @@ Before installation, please install libclangmm, see [installation guide](http:// ## Debian/Ubuntu ```sh -sudo apt-get install pkg-config libboost-system-dev libboost-thread-dev libboost-filesystem-dev libboost-log-dev libgtkmm-3.0-dev libgtksourceviewmm-3.0-dev libaspell-dev +sudo apt-get install pkg-config libboost-system-dev libboost-thread-dev libboost-filesystem-dev libboost-log-dev libgtkmm-3.0-dev libgtksourceviewmm-3.0-dev aspell-en libaspell-dev ``` ```sh git clone http://github.com/cppit/jucipp.git From d101ebcb470d70fc269f0ce9da774ca3cbad5c79 Mon Sep 17 00:00:00 2001 From: eidheim Date: Fri, 28 Aug 2015 14:51:37 +0200 Subject: [PATCH 41/54] Added spellcheck suggestions through tooltips. --- src/source.cc | 319 +++++++++++++++++++++++++++---------------------- src/source.h | 22 ++-- src/tooltips.h | 4 +- 3 files changed, 190 insertions(+), 155 deletions(-) diff --git a/src/source.cc b/src/source.cc index 82168b0..7492c27 100644 --- a/src/source.cc +++ b/src/source.cc @@ -77,6 +77,60 @@ Source::View::View(const boost::filesystem::path &file_path): file_path(file_pat if(Singleton::Config::source()->font.size()>0) override_font(Pango::FontDescription(Singleton::Config::source()->font)); + //Create tags for diagnostic warnings and errors: + auto scheme = get_source_buffer()->get_style_scheme(); + auto tag_table=get_buffer()->get_tag_table(); + auto style=scheme->get_style("def:warning"); + auto diagnostic_tag=get_source_buffer()->create_tag("def:warning"); + auto diagnostic_tag_underline=get_source_buffer()->create_tag("def:warning_underline"); + if(style && (style->property_foreground_set() || style->property_background_set())) { + Glib::ustring warning_property; + if(style->property_foreground_set()) { + warning_property=style->property_foreground().get_value(); + diagnostic_tag->property_foreground() = warning_property; + } + else if(style->property_background_set()) + warning_property=style->property_background().get_value(); + + diagnostic_tag_underline->property_underline()=Pango::Underline::UNDERLINE_ERROR; + auto tag_class=G_OBJECT_GET_CLASS(diagnostic_tag_underline->gobj()); //For older GTK+ 3 versions: + auto param_spec=g_object_class_find_property(tag_class, "underline-rgba"); + if(param_spec!=NULL) { + diagnostic_tag_underline->set_property("underline-rgba", Gdk::RGBA(warning_property)); + } + } + style=scheme->get_style("def:error"); + diagnostic_tag=get_source_buffer()->create_tag("def:error"); + diagnostic_tag_underline=get_source_buffer()->create_tag("def:error_underline"); + if(style && (style->property_foreground_set() || style->property_background_set())) { + Glib::ustring error_property; + if(style->property_foreground_set()) { + error_property=style->property_foreground().get_value(); + diagnostic_tag->property_foreground() = error_property; + } + else if(style->property_background_set()) + error_property=style->property_background().get_value(); + + diagnostic_tag_underline->property_underline()=Pango::Underline::UNDERLINE_ERROR; + auto tag_class=G_OBJECT_GET_CLASS(diagnostic_tag_underline->gobj()); //For older GTK+ 3 versions: + auto param_spec=g_object_class_find_property(tag_class, "underline-rgba"); + if(param_spec!=NULL) { + diagnostic_tag_underline->set_property("underline-rgba", Gdk::RGBA(error_property)); + } + } + //TODO: clear tag_class and param_spec? + + //Add tooltip foreground and background + style = scheme->get_style("def:note"); + auto note_tag=get_source_buffer()->create_tag("def:note_background"); + if(style->property_background_set()) { + note_tag->property_background()=style->property_background(); + } + note_tag=get_source_buffer()->create_tag("def:note"); + if(style->property_foreground_set()) { + note_tag->property_foreground()=style->property_foreground(); + } + tab_char=Singleton::Config::source()->default_tab_char; tab_size=Singleton::Config::source()->default_tab_size; if(Singleton::Config::source()->auto_tab_char_and_size) { @@ -137,6 +191,80 @@ Source::View::View(const boost::filesystem::path &file_path): file_path(file_pat } }); } + + set_tooltip_events(); +} + +void Source::View::set_tooltip_events() { + signal_motion_notify_event().connect([this](GdkEventMotion* event) { + if(on_motion_last_x!=event->x || on_motion_last_y!=event->y) { + delayed_tooltips_connection.disconnect(); + if(event->state==0) { + gdouble x=event->x; + gdouble y=event->y; + delayed_tooltips_connection=Glib::signal_timeout().connect([this, x, y]() { + Tooltips::init(); + Gdk::Rectangle rectangle(x, y, 1, 1); + if(source_readable) { + type_tooltips.show(rectangle); + diagnostic_tooltips.show(rectangle); + } + spellcheck_tooltips.show(rectangle); + return false; + }, 100); + } + type_tooltips.hide(); + diagnostic_tooltips.hide(); + spellcheck_tooltips.hide(); + } + on_motion_last_x=event->x; + on_motion_last_y=event->y; + return false; + }); + + get_buffer()->signal_mark_set().connect([this](const Gtk::TextBuffer::iterator& iterator, const Glib::RefPtr& mark) { + if(get_buffer()->get_has_selection() && mark->get_name()=="selection_bound") + delayed_tooltips_connection.disconnect(); + + if(mark->get_name()=="insert") { + delayed_tooltips_connection.disconnect(); + delayed_tooltips_connection=Glib::signal_timeout().connect([this]() { + Tooltips::init(); + Gdk::Rectangle rectangle; + get_iter_location(get_buffer()->get_insert()->get_iter(), rectangle); + int location_window_x, location_window_y; + buffer_to_window_coords(Gtk::TextWindowType::TEXT_WINDOW_TEXT, rectangle.get_x(), rectangle.get_y(), location_window_x, location_window_y); + rectangle.set_x(location_window_x-2); + rectangle.set_y(location_window_y); + rectangle.set_width(4); + if(source_readable) { + type_tooltips.show(rectangle); + diagnostic_tooltips.show(rectangle); + } + spellcheck_tooltips.show(rectangle); + return false; + }, 500); + type_tooltips.hide(); + diagnostic_tooltips.hide(); + spellcheck_tooltips.hide(); + } + }); + + signal_scroll_event().connect([this](GdkEventScroll* event) { + delayed_tooltips_connection.disconnect(); + type_tooltips.hide(); + diagnostic_tooltips.hide(); + spellcheck_tooltips.hide(); + return false; + }); + + signal_focus_out_event().connect([this](GdkEventFocus* event) { + delayed_tooltips_connection.disconnect(); + type_tooltips.hide(); + diagnostic_tooltips.hide(); + spellcheck_tooltips.hide(); + return false; + }); } void Source::View::search_occurrences_updated(GtkWidget* widget, GParamSpec* property, gpointer data) { @@ -510,21 +638,47 @@ void Source::View::spellcheck(Gtk::TextIter iter) { auto start=iter; auto end=iter; - while((*iter>=48 && *iter<=57) || (*iter>=65 && *iter<=90) || (*iter>=97 && *iter<=122) || *iter==95 || *iter>=128) { + while((*iter>=48 && *iter<=57) || (*iter>=65 && *iter<=90) || (*iter>=97 && *iter<=122) || *iter>=128) { start=iter; if(!iter.backward_char()) break; } - while((*end>=48 && *end<=57) || (*end>=65 && *end<=90) || (*end>=97 && *end<=122) || *end==95 || *end>=128) { + while((*end>=48 && *end<=57) || (*end>=65 && *end<=90) || (*end>=97 && *end<=122) || *end>=128) { if(!end.forward_char()) break; } + for(auto it=spellcheck_tooltips.begin();it!=spellcheck_tooltips.end();it++) { + if(it->start_mark->get_iter()==start || it->start_mark->get_iter()==it->end_mark->get_iter()) + it=spellcheck_tooltips.erase(it); + } auto word=get_buffer()->get_text(start, end); std::vector words; if(word.size()>0) { auto correct = aspell_speller_check(spellcheck_checker, word.data(), word.bytes()); - if(correct==0) + if(correct==0) { get_buffer()->apply_tag_by_name("spellcheck_error", start, end); + + const AspellWordList *suggestions = aspell_speller_suggest(spellcheck_checker, word.data(), word.bytes()); + AspellStringEnumeration *elements = aspell_word_list_elements(suggestions); + + auto words=std::make_shared(); + const char *word; + while ((word = aspell_string_enumeration_next(elements))!= NULL) { + if(words->size()==0) + *words="Suggestions:"; + (*words)+=std::string("\n")+word; + } + delete_aspell_string_enumeration(elements); + + if(words->size()>0) { + auto create_tooltip_buffer=[this, words]() { + auto tooltip_buffer=Gtk::TextBuffer::create(get_buffer()->get_tag_table()); + tooltip_buffer->insert_with_tag(tooltip_buffer->get_insert()->get_iter(), *words, "def:note"); + return tooltip_buffer; + }; + spellcheck_tooltips.emplace_back(create_tooltip_buffer, *this, get_buffer()->create_mark(start), get_buffer()->create_mark(end)); + } + } else get_buffer()->remove_tag_by_name("spellcheck_error", start, end); } @@ -577,59 +731,7 @@ Source::View(file_path), project_path(project_path) { DEBUG("Style " + item.second + " not found in " + scheme->get_name()); } } - INFO("Tagtable filled"); - - //Create tags for diagnostic warnings and errors: - auto style=scheme->get_style("def:warning"); - auto diagnostic_tag=get_source_buffer()->create_tag("def:warning"); - auto diagnostic_tag_underline=get_source_buffer()->create_tag("def:warning_underline"); - if(style && (style->property_foreground_set() || style->property_background_set())) { - Glib::ustring warning_property; - if(style->property_foreground_set()) { - warning_property=style->property_foreground().get_value(); - diagnostic_tag->property_foreground() = warning_property; - } - else if(style->property_background_set()) - warning_property=style->property_background().get_value(); - - diagnostic_tag_underline->property_underline()=Pango::Underline::UNDERLINE_ERROR; - auto tag_class=G_OBJECT_GET_CLASS(diagnostic_tag_underline->gobj()); //For older GTK+ 3 versions: - auto param_spec=g_object_class_find_property(tag_class, "underline-rgba"); - if(param_spec!=NULL) { - diagnostic_tag_underline->set_property("underline-rgba", Gdk::RGBA(warning_property)); - } - } - style=scheme->get_style("def:error"); - diagnostic_tag=get_source_buffer()->create_tag("def:error"); - diagnostic_tag_underline=get_source_buffer()->create_tag("def:error_underline"); - if(style && (style->property_foreground_set() || style->property_background_set())) { - Glib::ustring error_property; - if(style->property_foreground_set()) { - error_property=style->property_foreground().get_value(); - diagnostic_tag->property_foreground() = error_property; - } - else if(style->property_background_set()) - error_property=style->property_background().get_value(); - - diagnostic_tag_underline->property_underline()=Pango::Underline::UNDERLINE_ERROR; - auto tag_class=G_OBJECT_GET_CLASS(diagnostic_tag_underline->gobj()); //For older GTK+ 3 versions: - auto param_spec=g_object_class_find_property(tag_class, "underline-rgba"); - if(param_spec!=NULL) { - diagnostic_tag_underline->set_property("underline-rgba", Gdk::RGBA(error_property)); - } - } - //TODO: clear tag_class and param_spec? - - //Add tooltip foreground and background - style = scheme->get_style("def:note"); - auto note_tag=get_source_buffer()->create_tag("def:note_background"); - if(style->property_background_set()) { - note_tag->property_background()=style->property_background(); - } - note_tag=get_source_buffer()->create_tag("def:note"); - if(style->property_foreground_set()) { - note_tag->property_foreground()=style->property_foreground(); - } + INFO("Tagtable filled"); parsing_in_progress=Singleton::terminal()->print_in_progress("Parsing "+file_path.string()); //GTK-calls must happen in main thread, so the parse_thread @@ -649,7 +751,7 @@ Source::View(file_path), project_path(project_path) { update_syntax(); update_diagnostics(); update_types(); - clang_readable=true; + source_readable=true; set_status(""); parsing_mutex.unlock(); INFO("Syntax updated"); @@ -666,10 +768,9 @@ Source::View(file_path), project_path(project_path) { start_reparse(); type_tooltips.hide(); diagnostic_tooltips.hide(); + spellcheck_tooltips.hide(); }); - get_buffer()->signal_mark_set().connect(sigc::mem_fun(*this, &Source::ClangViewParse::on_mark_set), false); - bracket_regex=std::regex(std::string("^(")+tab_char+"*).*\\{ *$"); no_bracket_statement_regex=std::regex(std::string("^(")+tab_char+"*)(if|for|else if|catch|while) *\\(.*[^;}] *$"); no_bracket_no_para_statement_regex=std::regex(std::string("^(")+tab_char+"*)(else|try|do) *$"); @@ -678,8 +779,9 @@ Source::View(file_path), project_path(project_path) { void Source::ClangViewParse::init_parse() { type_tooltips.hide(); diagnostic_tooltips.hide(); + spellcheck_tooltips.hide(); get_buffer()->remove_all_tags(get_buffer()->begin(), get_buffer()->end()); - clang_readable=false; + source_readable=false; parse_thread_go=true; parse_thread_mapped=false; parse_thread_stop=false; @@ -743,10 +845,10 @@ std::map Source::ClangViewParse::get_buffer_map() cons void Source::ClangViewParse::start_reparse() { parse_thread_mapped=false; - clang_readable=false; + source_readable=false; delayed_reparse_connection.disconnect(); delayed_reparse_connection=Glib::signal_timeout().connect([this]() { - clang_readable=false; + source_readable=false; parse_thread_go=true; set_status("parsing..."); return false; @@ -915,70 +1017,6 @@ void Source::ClangViewParse::update_types() { } } -bool Source::ClangViewParse::on_motion_notify_event(GdkEventMotion* event) { - if(on_motion_last_x!=event->x || on_motion_last_y!=event->y) { - delayed_tooltips_connection.disconnect(); - if(event->state==0) { - gdouble x=event->x; - gdouble y=event->y; - delayed_tooltips_connection=Glib::signal_timeout().connect([this, x, y]() { - if(clang_readable) { - Gdk::Rectangle rectangle(x, y, 1, 1); - Tooltips::init(); - type_tooltips.show(rectangle); - diagnostic_tooltips.show(rectangle); - } - return false; - }, 100); - } - type_tooltips.hide(); - diagnostic_tooltips.hide(); - } - on_motion_last_x=event->x; - on_motion_last_y=event->y; - return Source::View::on_motion_notify_event(event); -} - -void Source::ClangViewParse::on_mark_set(const Gtk::TextBuffer::iterator& iterator, const Glib::RefPtr& mark) { - if(get_buffer()->get_has_selection() && mark->get_name()=="selection_bound") - delayed_tooltips_connection.disconnect(); - - if(mark->get_name()=="insert") { - delayed_tooltips_connection.disconnect(); - delayed_tooltips_connection=Glib::signal_timeout().connect([this]() { - if(clang_readable) { - Gdk::Rectangle rectangle; - get_iter_location(get_buffer()->get_insert()->get_iter(), rectangle); - int location_window_x, location_window_y; - buffer_to_window_coords(Gtk::TextWindowType::TEXT_WINDOW_TEXT, rectangle.get_x(), rectangle.get_y(), location_window_x, location_window_y); - rectangle.set_x(location_window_x-2); - rectangle.set_y(location_window_y); - rectangle.set_width(4); - Tooltips::init(); - type_tooltips.show(rectangle); - diagnostic_tooltips.show(rectangle); - } - return false; - }, 500); - type_tooltips.hide(); - diagnostic_tooltips.hide(); - } -} - -bool Source::ClangViewParse::on_focus_out_event(GdkEventFocus* event) { - delayed_tooltips_connection.disconnect(); - type_tooltips.hide(); - diagnostic_tooltips.hide(); - return Source::View::on_focus_out_event(event); -} - -bool Source::ClangViewParse::on_scroll_event(GdkEventScroll* event) { - delayed_tooltips_connection.disconnect(); - type_tooltips.hide(); - diagnostic_tooltips.hide(); - return Source::View::on_scroll_event(event); -} - //Clang indentation //TODO: replace indentation methods with a better implementation or maybe use libclang bool Source::ClangViewParse::on_key_press_event(GdkEventKey* key) { @@ -1128,6 +1166,14 @@ Source::ClangViewParse(file_path, project_path), autocomplete_cancel_starting(fa return false; }, false); + signal_focus_out_event().connect([this](GdkEventFocus* event) { + autocomplete_cancel_starting=true; + if(completion_dialog_shown) { + completion_dialog->hide(); + } + + return false; + }); } bool Source::ClangViewAutocomplete::on_key_press_event(GdkEventKey *key) { @@ -1139,15 +1185,6 @@ bool Source::ClangViewAutocomplete::on_key_press_event(GdkEventKey *key) { return ClangViewParse::on_key_press_event(key); } -bool Source::ClangViewAutocomplete::on_focus_out_event(GdkEventFocus* event) { - autocomplete_cancel_starting=true; - if(completion_dialog_shown) { - completion_dialog->hide(); - } - - return Source::ClangViewParse::on_focus_out_event(event); -} - void Source::ClangViewAutocomplete::start_autocomplete() { if(!has_focus()) return; @@ -1333,7 +1370,7 @@ Source::ClangViewAutocomplete(file_path, project_path) { }); get_token=[this]() -> std::string { - if(clang_readable) { + if(source_readable) { auto iter=get_buffer()->get_insert()->get_iter(); auto line=(unsigned)iter.get_line(); auto index=(unsigned)iter.get_line_index(); @@ -1351,7 +1388,7 @@ Source::ClangViewAutocomplete(file_path, project_path) { }; get_token_name=[this]() -> std::string { - if(clang_readable) { + if(source_readable) { auto iter=get_buffer()->get_insert()->get_iter(); auto line=(unsigned)iter.get_line(); auto index=(unsigned)iter.get_line_index(); @@ -1367,7 +1404,7 @@ Source::ClangViewAutocomplete(file_path, project_path) { }; tag_similar_tokens=[this](const std::string &usr){ - if(clang_readable) { + if(source_readable) { if(usr.size()>0 && last_similar_tokens_tagged!=usr) { get_buffer()->remove_tag(similar_tokens_tag, get_buffer()->begin(), get_buffer()->end()); auto offsets=clang_tokens->get_similar_token_offsets(usr); @@ -1385,7 +1422,7 @@ Source::ClangViewAutocomplete(file_path, project_path) { rename_similar_tokens=[this](const std::string &usr, const std::string &text) { size_t number=0; - if(clang_readable) { + if(source_readable) { auto offsets=clang_tokens->get_similar_token_offsets(usr); std::vector, Glib::RefPtr > > marks; for(auto &offset: offsets) { @@ -1419,7 +1456,7 @@ Source::ClangViewAutocomplete(file_path, project_path) { get_declaration_location=[this](){ std::pair location; - if(clang_readable) { + if(source_readable) { auto iter=get_buffer()->get_insert()->get_iter(); auto line=(unsigned)iter.get_line(); auto index=(unsigned)iter.get_line_index(); @@ -1440,7 +1477,7 @@ Source::ClangViewAutocomplete(file_path, project_path) { }; goto_method=[this](){ - if(clang_readable) { + if(source_readable) { selection_dialog=std::unique_ptr(new SelectionDialog(*this, get_buffer()->create_mark(get_buffer()->get_insert()->get_iter()))); auto rows=std::make_shared >(); auto methods=clang_tokens->get_cxx_methods(); diff --git a/src/source.h b/src/source.h index 9a8dd15..8df142e 100644 --- a/src/source.h +++ b/src/source.h @@ -76,11 +76,20 @@ namespace Source { std::function on_update_status; std::string status; protected: + bool source_readable; + Tooltips diagnostic_tooltips; + Tooltips type_tooltips; + Tooltips spellcheck_tooltips; + gdouble on_motion_last_x; + gdouble on_motion_last_y; + sigc::connection delayed_tooltips_connection; + void set_tooltip_events(); + void set_status(const std::string &status); std::string get_line(size_t line_number); std::string get_line_before_insert(); - + bool on_key_press_event(GdkEventKey* key); bool on_button_press_event(GdkEventButton *event); @@ -112,13 +121,10 @@ namespace Source { protected: void init_parse(); bool on_key_press_event(GdkEventKey* key); - bool on_focus_out_event(GdkEventFocus* event); std::unique_ptr clang_tu; std::mutex parsing_mutex; std::unique_ptr clang_tokens; - bool clang_readable; sigc::connection delayed_reparse_connection; - sigc::connection delayed_tooltips_connection; std::shared_ptr parsing_in_progress; std::thread parse_thread; @@ -136,14 +142,7 @@ namespace Source { std::set last_syntax_tags; void update_diagnostics(); void update_types(); - Tooltips diagnostic_tooltips; - Tooltips type_tooltips; - bool on_motion_notify_event(GdkEventMotion* event); - gdouble on_motion_last_x; - gdouble on_motion_last_y; - void on_mark_set(const Gtk::TextBuffer::iterator& iterator, const Glib::RefPtr& mark); - bool on_scroll_event(GdkEventScroll* event); static clang::Index clang_index; std::vector get_compilation_commands(); @@ -160,7 +159,6 @@ namespace Source { ClangViewAutocomplete(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path); protected: bool on_key_press_event(GdkEventKey* key); - bool on_focus_out_event(GdkEventFocus* event); std::thread autocomplete_thread; private: void start_autocomplete(); diff --git a/src/tooltips.h b/src/tooltips.h index 3d52c27..9330394 100644 --- a/src/tooltips.h +++ b/src/tooltips.h @@ -14,13 +14,13 @@ public: Gdk::Rectangle activation_rectangle; std::unique_ptr window; + Glib::RefPtr start_mark; + Glib::RefPtr end_mark; private: void wrap_lines(Glib::RefPtr text_buffer); std::function()> create_tooltip_buffer; std::unique_ptr tooltip_widget; - Glib::RefPtr start_mark; - Glib::RefPtr end_mark; Gtk::TextView& text_view; int tooltip_width, tooltip_height; }; From db0b67ceb7440cd749a7b2c8f98aa08849b7060c Mon Sep 17 00:00:00 2001 From: eidheim Date: Fri, 28 Aug 2015 15:13:10 +0200 Subject: [PATCH 42/54] Spellcheck suggestions now separated with ', ' instead of newline. --- src/source.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/source.cc b/src/source.cc index 7492c27..860c593 100644 --- a/src/source.cc +++ b/src/source.cc @@ -664,9 +664,12 @@ void Source::View::spellcheck(Gtk::TextIter iter) { auto words=std::make_shared(); const char *word; while ((word = aspell_string_enumeration_next(elements))!= NULL) { - if(words->size()==0) - *words="Suggestions:"; - (*words)+=std::string("\n")+word; + if(words->size()==0) { + *words="Suggestions:\n"; + (*words)+=word; + } + else + (*words)+=std::string(", ")+word; } delete_aspell_string_enumeration(elements); From cfc01bfe52329bdea05da84236485bcfa093fc6f Mon Sep 17 00:00:00 2001 From: eidheim Date: Fri, 28 Aug 2015 16:32:27 +0200 Subject: [PATCH 43/54] Added spell checking. --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 40ec707..cdd9210 100644 --- a/README.md +++ b/README.md @@ -7,13 +7,14 @@ towards libclang with speed in mind. ## Features * Fast and responsive -* Syntax highlighing (even C++11/14, and 118 other file types) +* Syntax highlighing (even C++11/14, and more than 100 other file types) * C++ warnings and errors on the fly * Fast C++ autocomletion (even external libraries) * Tooltips showing type information and doxygen documentation * Accurate refactoring across files -* Basic editor functionallity * Highlighting of similar types +* Spell checking of comments and strings +* Basic editor functionallity * Write your own plugins in python (disabled at the moment) ## Dependencies ## @@ -24,7 +25,8 @@ towards libclang with speed in mind. * libboost-system-dev * libgtkmm-3.0-dev * libgtksourceview2.0-dev -* libgtksourceviewmm-3.0-dev +* libgtksourceviewmm-3.0-dev +* libaspell-dev * libclang-dev * [libclangmm](http://github.com/cppit/libclangmm/) From db6f5847624c8de04562351431d407c60be3f825 Mon Sep 17 00:00:00 2001 From: eidheim Date: Fri, 28 Aug 2015 17:52:25 +0200 Subject: [PATCH 44/54] Fixed CMakeLists so that the CMAKE_INSTALL_PREFIX can be used (for making MSYS2 package for instance). --- CMakeLists.txt | 7 ----- .../{ => mingw-w64-gtksourceview3}/LICENSE | 0 .../mingw-w64-gtksourceviewmm3/LICENSE | 27 +++++++++++++++++++ docs/install.md | 2 +- src/CMakeLists.txt | 5 ++-- 5 files changed, 31 insertions(+), 10 deletions(-) rename MINGW-packages/{ => mingw-w64-gtksourceview3}/LICENSE (100%) create mode 100644 MINGW-packages/mingw-w64-gtksourceviewmm3/LICENSE diff --git a/CMakeLists.txt b/CMakeLists.txt index 045f920..f80481f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,13 +3,6 @@ cmake_minimum_required (VERSION 2.8.4) set(project_name juci) #set(module juci_to_python_api) -if(MSYS) - string(TOLOWER "/$ENV{MSYSTEM}" MSYS_PATH) - set(bin_install_path "${MSYS_PATH}/bin") -else() - set(bin_install_path "/usr/local/bin") -endif() - #set(lib_install_path "/usr/local/lib/python2.7/dist-packages/") project (${project_name}) diff --git a/MINGW-packages/LICENSE b/MINGW-packages/mingw-w64-gtksourceview3/LICENSE similarity index 100% rename from MINGW-packages/LICENSE rename to MINGW-packages/mingw-w64-gtksourceview3/LICENSE diff --git a/MINGW-packages/mingw-w64-gtksourceviewmm3/LICENSE b/MINGW-packages/mingw-w64-gtksourceviewmm3/LICENSE new file mode 100644 index 0000000..e0f07ba --- /dev/null +++ b/MINGW-packages/mingw-w64-gtksourceviewmm3/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2013, Алексей +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + +* Neither the name of the {organization} nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/docs/install.md b/docs/install.md index 7764368..534a930 100644 --- a/docs/install.md +++ b/docs/install.md @@ -58,7 +58,7 @@ cd ../../ Compile and install juCi++ source: ```sh -cmake -G"MSYS Makefiles" . +cmake -G"MSYS Makefiles" -DCMAKE_INSTALL_PREFIX=/mingw[32 or 64] . make make install ``` diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3dcada4..2d43bff 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -39,8 +39,9 @@ validate(${LCL_FOUND} "clangmm" "clangmm" "clangmm") find_package(LibClang) validate(${LIBCLANG_FOUND} "clang" "libclang-dev" "llvm") +#TODO: till clang is fixed on MSYS2 ((lib)clang.dll.a is missing): if(MSYS) - set(LIBCLANG_LIBRARIES "${MSYS_PATH}/bin/clang.dll") + set(LIBCLANG_LIBRARIES "${CMAKE_INSTALL_PREFIX}/bin/clang.dll") endif() #find_package(PythonLibs 2.7) @@ -137,7 +138,7 @@ if(${validation}) # install(TARGETS ${project_name} ${module} install(TARGETS ${project_name} - RUNTIME DESTINATION ${bin_install_path} + RUNTIME DESTINATION bin # LIBRARY DESTINATION ${lib_install_path} ) endif(${validation}) From a78aef928afbb10111dfb90fed37221a84b848cf Mon Sep 17 00:00:00 2001 From: eidheim Date: Sat, 29 Aug 2015 10:24:18 +0200 Subject: [PATCH 45/54] make install now works on Windows. --- docs/install.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/install.md b/docs/install.md index 534a930..8ddcac3 100644 --- a/docs/install.md +++ b/docs/install.md @@ -62,7 +62,6 @@ cmake -G"MSYS Makefiles" -DCMAKE_INSTALL_PREFIX=/mingw[32 or 64] . make make install ``` -**You might have to install juci manually**