Browse Source

Merge branch 'eidheim-master'

merge-requests/365/head
eidheim 10 years ago
parent
commit
9bea94942a
  1. 3
      .gitmodules
  2. 15
      MINGW-packages/mingw-w64-gtksourceview3/0006-hack-convert-path-back-to-unix.patch
  3. 27
      MINGW-packages/mingw-w64-gtksourceview3/LICENSE
  4. 64
      MINGW-packages/mingw-w64-gtksourceview3/PKGBUILD
  5. 27
      MINGW-packages/mingw-w64-gtksourceviewmm3/LICENSE
  6. 33
      MINGW-packages/mingw-w64-gtksourceviewmm3/PKGBUILD
  7. 1
      README.md
  8. 14
      docs/install.md
  9. 11
      src/CMakeLists.txt
  10. 41
      src/config.cc
  11. 3
      src/config.h
  12. 2
      src/dialogs.cc
  13. 63
      src/files.h
  14. 24
      src/juci.cc
  15. 1
      src/juci.h
  16. 396
      src/menu.cc
  17. 17
      src/menu.h
  18. 25
      src/notebook.cc
  19. 2
      src/notebook.h
  20. 16
      src/singletons.cc
  21. 4
      src/singletons.h
  22. 33
      src/source.cc
  23. 2
      src/source.h
  24. 80
      src/source_clang.cc
  25. 24
      src/source_clang.h
  26. 108
      src/terminal.cc
  27. 4
      src/terminal.h
  28. 227
      src/terminal_win.cc
  29. 387
      src/window.cc
  30. 10
      src/window.h

3
.gitmodules vendored

@ -1,3 +1,4 @@
[submodule "libclangmm"] [submodule "libclangmm"]
path = libclangmm path = libclangmm
url = https://github.com/cppit/libclangmm/tree/v0.9.3 url = https://github.com/cppit/libclangmm.git
branch = v0.9.3

15
MINGW-packages/mingw-w64-gtksourceview3/0006-hack-convert-path-back-to-unix.patch

@ -1,15 +0,0 @@
--- 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"],

27
MINGW-packages/mingw-w64-gtksourceview3/LICENSE

@ -1,27 +0,0 @@
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.

64
MINGW-packages/mingw-w64-gtksourceview3/PKGBUILD

@ -1,64 +0,0 @@
# Maintainer: Alexey Pavlov <alexpux@gmail.com>
_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"
}

27
MINGW-packages/mingw-w64-gtksourceviewmm3/LICENSE

@ -1,27 +0,0 @@
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.

33
MINGW-packages/mingw-w64-gtksourceviewmm3/PKGBUILD

@ -1,33 +0,0 @@
_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=${pkgver}")
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
}

1
README.md

@ -22,6 +22,7 @@ towards libclang with speed and ease of use in mind.
* Run shell commands within JuCi++, even on Windows * Run shell commands within JuCi++, even on Windows
* Regex search and replace * Regex search and replace
* Smart paste, keys and indentation * Smart paste, keys and indentation
* Auto-indentation of C++ file buffers through [clang-format](http://clang.llvm.org/docs/ClangFormat.html)
* Source minimap * Source minimap
* Full UTF-8 support * Full UTF-8 support

14
docs/install.md

@ -15,6 +15,12 @@ make
sudo make install sudo make install
``` ```
To use clang-format for auto-indentation of C++ files (replace \[version\] with an available clang-format version):
```sh
sudo apt-get install clang-format-[version]
sudo ln -s /usr/bin/clang-format-[version] /usr/local/bin/clang-format
```
## Ubuntu 14/Linux Mint 17 ## Ubuntu 14/Linux Mint 17
Install dependencies: Install dependencies:
```sh ```sh
@ -34,10 +40,16 @@ make
sudo make install sudo make install
``` ```
To use clang-format for auto-indentation of C++ files (replace \[version\] with an available clang-format version):
```sh
sudo apt-get install clang-format-[version]
sudo ln -s /usr/bin/clang-format-[version] /usr/local/bin/clang-format
```
## OS X with Homebrew (http://brew.sh/) ## OS X with Homebrew (http://brew.sh/)
Install dependencies (installing llvm may take some time): Install dependencies (installing llvm may take some time):
```sh ```sh
brew install cmake --with-clang llvm pkg-config boost gtkmm3 homebrew/x11/gtksourceviewmm3 aspell brew install cmake --with-clang llvm pkg-config boost gtkmm3 homebrew/x11/gtksourceviewmm3 aspell clang-format
``` ```
Get juCi++ source, compile and install: Get juCi++ source, compile and install:

11
src/CMakeLists.txt

@ -10,6 +10,17 @@ if(APPLE)
set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:/usr/local/lib/pkgconfig:/opt/X11/lib/pkgconfig") set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:/usr/local/lib/pkgconfig:/opt/X11/lib/pkgconfig")
endif() endif()
if(UNIX) #Checking if compiling on Ubuntu that has a buggy menu system
find_program(LSB_RELEASE_BIN lsb_release)
if(LSB_RELEASE_BIN)
execute_process(COMMAND ${LSB_RELEASE_BIN} -is
OUTPUT_VARIABLE DISTRIBUTION OUTPUT_STRIP_TRAILING_WHITESPACE)
if(DISTRIBUTION STREQUAL Ubuntu)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUBUNTU_BUGGED_MENU")
endif()
endif()
endif()
INCLUDE(FindPkgConfig) INCLUDE(FindPkgConfig)
find_package(LibClang REQUIRED) find_package(LibClang REQUIRED)

41
src/config.cc

@ -8,28 +8,23 @@
using namespace std; //TODO: remove using namespace std; //TODO: remove
MainConfig::MainConfig() { MainConfig::MainConfig() {
auto search_envs = init_home_path(); init_home_path();
}
void MainConfig::read() {
auto config_json = (home/"config"/"config.json").string(); // This causes some redundant copies, but assures windows support auto config_json = (home/"config"/"config.json").string(); // This causes some redundant copies, but assures windows support
try { try {
find_or_create_config_files(); find_or_create_config_files();
if(home.empty()) {
std::string searched_envs = "[";
for(auto &env : search_envs)
searched_envs+=env+", ";
searched_envs.erase(searched_envs.end()-2, searched_envs.end());
searched_envs+="]";
throw std::runtime_error("One of these environment variables needs to point to a writable directory to save configuration: " + searched_envs);
}
boost::property_tree::json_parser::read_json(config_json, cfg); boost::property_tree::json_parser::read_json(config_json, cfg);
update_config_file(); update_config_file();
retrieve_config(); retrieve_config();
} }
catch(const std::exception &e) { catch(const std::exception &e) {
Singleton::terminal()->print("Error reading "+config_json + "config.json: "+e.what()+"\n");
std::stringstream ss; std::stringstream ss;
ss << configjson; ss << configjson;
boost::property_tree::read_json(ss, cfg); boost::property_tree::read_json(ss, cfg);
retrieve_config(); retrieve_config();
JERROR("Error reading "+ config_json + ": "+e.what()+"\n"); // logs will print to cerr when init_log haven't been run yet
} }
cfg.clear(); cfg.clear();
} }
@ -63,7 +58,10 @@ void MainConfig::find_or_create_config_files() {
} }
void MainConfig::retrieve_config() { void MainConfig::retrieve_config() {
Singleton::Config::window()->keybindings = cfg.get_child("keybindings"); auto keybindings_pt = cfg.get_child("keybindings");
for (auto &i : keybindings_pt) {
Singleton::Config::menu()->keys[i.first] = i.second.get_value<std::string>();
}
GenerateSource(); GenerateSource();
GenerateDirectoryFilter(); GenerateDirectoryFilter();
@ -146,7 +144,9 @@ void MainConfig::GenerateSource() {
for (auto &i : source_json.get_child("clang_types")) for (auto &i : source_json.get_child("clang_types"))
source_cfg->clang_types[i.first] = i.second.get_value<std::string>(); source_cfg->clang_types[i.first] = i.second.get_value<std::string>();
source_cfg->clang_format_style = source_json.get<std::string>("clang_format_style");
auto pt_doc_search=cfg.get_child("documentation_searches"); auto pt_doc_search=cfg.get_child("documentation_searches");
for(auto &pt_doc_search_lang: pt_doc_search) { for(auto &pt_doc_search_lang: pt_doc_search) {
source_cfg->documentation_searches[pt_doc_search_lang.first].separator=pt_doc_search_lang.second.get<std::string>("separator"); source_cfg->documentation_searches[pt_doc_search_lang.first].separator=pt_doc_search_lang.second.get<std::string>("separator");
@ -167,7 +167,8 @@ void MainConfig::GenerateDirectoryFilter() {
for ( auto &i : ignore_json ) for ( auto &i : ignore_json )
dir_cfg->ignored.emplace_back(i.second.get_value<std::string>()); dir_cfg->ignored.emplace_back(i.second.get_value<std::string>());
} }
std::vector<std::string> MainConfig::init_home_path(){
void MainConfig::init_home_path(){
std::vector<std::string> locations = JUCI_ENV_SEARCH_LOCATIONS; std::vector<std::string> locations = JUCI_ENV_SEARCH_LOCATIONS;
char *ptr = nullptr; char *ptr = nullptr;
for (auto &env : locations) { for (auto &env : locations) {
@ -178,9 +179,17 @@ std::vector<std::string> MainConfig::init_home_path(){
if (boost::filesystem::exists(ptr)) { if (boost::filesystem::exists(ptr)) {
home /= ptr; home /= ptr;
home /= ".juci"; home /= ".juci";
return locations; break;
} }
} }
home="";
return locations; if(home.empty()) {
std::string searched_envs = "[";
for(auto &env : locations)
searched_envs+=env+", ";
searched_envs.erase(searched_envs.end()-2, searched_envs.end());
searched_envs+="]";
throw std::runtime_error("One of these environment variables needs to point to a writable directory to save configuration: " + searched_envs);
}
return;
} }

3
src/config.h

@ -7,6 +7,7 @@
class MainConfig { class MainConfig {
public: public:
MainConfig(); MainConfig();
void read();
const boost::filesystem::path& juci_home_path() const { return home; } const boost::filesystem::path& juci_home_path() const { return home; }
private: private:
@ -18,7 +19,7 @@ private:
void GenerateSource(); void GenerateSource();
void GenerateDirectoryFilter(); void GenerateDirectoryFilter();
std::vector<std::string> init_home_path(); void init_home_path();
boost::property_tree::ptree cfg; boost::property_tree::ptree cfg;
boost::filesystem::path home; boost::filesystem::path home;
}; };

2
src/dialogs.cc

@ -40,7 +40,7 @@ std::string Dialog::new_folder() {
} }
std::string Dialog::select_file() { std::string Dialog::select_file() {
return open_dialog("Please choose a folder", return open_dialog("Please choose a file",
{std::make_pair("Cancel", Gtk::RESPONSE_CANCEL),std::make_pair("Select", Gtk::RESPONSE_OK)}, {std::make_pair("Cancel", Gtk::RESPONSE_CANCEL),std::make_pair("Select", Gtk::RESPONSE_OK)},
Gtk::FILE_CHOOSER_ACTION_OPEN); Gtk::FILE_CHOOSER_ACTION_OPEN);
} }

63
src/files.h

@ -1,6 +1,6 @@
#include <string> #include <string>
#define JUCI_VERSION "0.9.3" #define JUCI_VERSION "0.9.4"
#define JUCI_ENV_SEARCH_LOCATIONS {"AppData", "HOME", "JUCI_HOME"} #define JUCI_ENV_SEARCH_LOCATIONS {"AppData", "HOME", "JUCI_HOME"}
@ -13,24 +13,36 @@ const std::string configjson =
" },\n" " },\n"
" \"terminal_history_size\": 1000,\n" " \"terminal_history_size\": 1000,\n"
" \"gtk_theme\": {\n" " \"gtk_theme\": {\n"
" \"name\": \"Adwaita\", //Use \"\" for default theme, At least these two exist on all systems: Adwaita, Raleigh\n" " \"name_comment\": \"Use \\\"\\\" for default theme, At least these two exist on all systems: Adwaita, Raleigh\",\n"
" \"variant\": \"\" //Use \"\" for default variant, and \"dark\" for dark theme variant\n" " \"name\": \"Adwaita\",\n"
" \"variant_comment\": \"Use \\\"\\\" for default variant, and \\\"dark\\\" for dark theme variant\",\n"
" \"variant\": \"\"\n"
" },\n" " },\n"
" \"source\": {\n" " \"source\": {\n"
" \"style\": \"juci-light\", //Use \"\" for default style, and for instance juci-dark or juci-dark-blue together with dark gtk_theme variant. Styles from normal gtksourceview install: classic, cobalt, kate, oblivion, solarized-dark, solarized-light, tango\n" " \"style_comment\": \"Use \\\"\\\" for default style, and for instance juci-dark or juci-dark-blue together with dark gtk_theme variant. Styles from normal gtksourceview install: classic, cobalt, kate, oblivion, solarized-dark, solarized-light, tango\",\n"
" \"style\": \"juci-light\",\n"
" \"font_comment\": \"Use \\\"\\\" for default font, and for instance \\\"Monospace 12\\\" to also set size\",\n"
#ifdef __APPLE__ #ifdef __APPLE__
" \"font\": \"Menlo 11\", " " \"font\": \"Menlo 11\",\n"
#else #else
#ifdef _WIN32 #ifdef _WIN32
" \"font\": \"Consolas\", " " \"font\": \"Consolas\",\n"
#else #else
" \"font\": \"Monospace\", " " \"font\": \"Monospace\",\n"
#endif #endif
#endif #endif
"//Use \"\" for default font, and for instance \"Monospace 12\" to also set size.\n"
" \"show_map\": true,\n" " \"show_map\": true,\n"
" \"map_font_size\": \"1\",\n" " \"map_font_size\": \"1\",\n"
" \"spellcheck_language\": \"en_US\", //Use \"\" to set language from your locale settings\n" " \"spellcheck_language_comment\": \"Use \\\"\\\" to set language from your locale settings\",\n"
" \"spellcheck_language\": \"en_US\",\n"
" \"auto_tab_char_and_size_comment\": \"Use false to always use default tab char and size\",\n"
" \"auto_tab_char_and_size\": true,\n"
" \"default_tab_char_comment\": \"Use \\\"\\t\\\" for regular tab\",\n"
" \"default_tab_char\": \" \",\n"
" \"default_tab_size\": 2,\n"
" \"wrap_lines\": false,\n"
" \"highlight_current_line\": true,\n"
" \"show_line_numbers\": true,\n"
" \"clang_types\": {\n" " \"clang_types\": {\n"
" \"8\": \"def:function\",\n" " \"8\": \"def:function\",\n"
" \"21\": \"def:function\",\n" " \"21\": \"def:function\",\n"
@ -45,40 +57,36 @@ const std::string configjson =
" \"702\": \"def:statement\",\n" " \"702\": \"def:statement\",\n"
" \"705\": \"def:comment\"\n" " \"705\": \"def:comment\"\n"
" },\n" " },\n"
" \"auto_tab_char_and_size\": true, //Use false to always use default tab char and size\n" " \"clang_format_style_comment\": \"IndentWidth, AccessModifierOffset and UseTab are set automatically. See http://clang.llvm.org/docs/ClangFormatStyleOptions.html\",\n"
" \"default_tab_char\": \" \", //Use \"\\t\" for regular tab\n" " \"clang_format_style\": \"ColumnLimit: 0\"\n"
" \"default_tab_size\": 2,\n"
" \"wrap_lines\": false,\n"
" \"highlight_current_line\": true,\n"
" \"show_line_numbers\": true\n"
" },\n" " },\n"
" \"keybindings\": {\n" " \"keybindings\": {\n"
" \"preferences\": \"<primary>comma\",\n"
" \"quit\": \"<primary>q\",\n"
" \"new_file\": \"<primary>n\",\n" " \"new_file\": \"<primary>n\",\n"
" \"new_folder\": \"<primary><shift>n\",\n" " \"new_folder\": \"<primary><shift>n\",\n"
" \"open_folder\": \"<primary><shift>o\",\n"
" \"open_file\": \"<primary>o\",\n" " \"open_file\": \"<primary>o\",\n"
" \"open_folder\": \"<primary><shift>o\",\n"
" \"save\": \"<primary>s\",\n" " \"save\": \"<primary>s\",\n"
" \"save_as\": \"<primary><shift>s\",\n" " \"save_as\": \"<primary><shift>s\",\n"
" \"preferences\": \"<primary>comma\",\n"
" \"quit\": \"<primary>q\",\n"
" \"edit_copy\": \"<primary>c\",\n"
" \"edit_cut\": \"<primary>x\",\n"
" \"edit_paste\": \"<primary>v\",\n"
" \"edit_undo\": \"<primary>z\",\n" " \"edit_undo\": \"<primary>z\",\n"
" \"edit_redo\": \"<primary><shift>z\",\n" " \"edit_redo\": \"<primary><shift>z\",\n"
" \"edit_cut\": \"<primary>x\",\n"
" \"edit_copy\": \"<primary>c\",\n"
" \"edit_paste\": \"<primary>v\",\n"
" \"edit_find\": \"<primary>f\",\n" " \"edit_find\": \"<primary>f\",\n"
" \"edit_set_tab\": \"\",\n" " \"edit_set_tab\": \"\",\n"
" \"source_spellcheck\": \"\",\n" " \"source_spellcheck\": \"\",\n"
" \"source_spellcheck_clear\": \"\",\n" " \"source_spellcheck_clear\": \"\",\n"
" \"source_spellcheck_next_error\": \"<primary><shift>e\",\n" " \"source_spellcheck_next_error\": \"<primary><shift>e\",\n"
" \"source_indentation_set_buffer_tab\": \"\",\n" " \"source_indentation_set_buffer_tab\": \"\",\n"
" \"source_indentation_auto_indent_buffer\": \"\",\n" " \"source_indentation_auto_indent_buffer\": \"<primary><shift>i\",\n"
" \"source_goto_line\": \"<primary>g\",\n" " \"source_goto_line\": \"<primary>g\",\n"
" \"source_center_cursor\": \"<primary>l\",\n" " \"source_center_cursor\": \"<primary>l\",\n"
" \"source_find_documentation\": \"<primary><shift>d\",\n"
" \"source_goto_declaration\": \"<primary>d\",\n" " \"source_goto_declaration\": \"<primary>d\",\n"
" \"source_goto_method\": \"<primary>m\",\n" " \"source_goto_method\": \"<primary>m\",\n"
" \"source_rename\": \"<primary>r\",\n" " \"source_rename\": \"<primary>r\",\n"
" \"source_find_documentation\": \"<primary><shift>d\",\n"
" \"source_goto_next_diagnostic\": \"<primary>e\",\n" " \"source_goto_next_diagnostic\": \"<primary>e\",\n"
" \"source_apply_fix_its\": \"<control>space\",\n" " \"source_apply_fix_its\": \"<control>space\",\n"
" \"compile_and_run\": \"<primary>Return\",\n" " \"compile_and_run\": \"<primary>Return\",\n"
@ -139,10 +147,11 @@ const std::string juci_light_style =
" <color name=\"purple\" value=\"#990099\"/>\n" " <color name=\"purple\" value=\"#990099\"/>\n"
"\n" "\n"
" <style name=\"text\" foreground=\"#000000\" background=\"#FFFFFF\"/>\n" " <style name=\"text\" foreground=\"#000000\" background=\"#FFFFFF\"/>\n"
" <style name=\"background-pattern\" background=\"#rgba(0,0,0,.03)\"/>\n"
" <style name=\"selection\" background=\"#4A90D9\"/>\n" " <style name=\"selection\" background=\"#4A90D9\"/>\n"
"\n" "\n"
" <!-- Current Line Highlighting -->\n" " <!-- Current Line Highlighting -->\n"
" <style name=\"current-line\" background=\"#EEEEEE\"/>\n" " <style name=\"current-line\" background=\"#rgba(0,0,0,.07)\"/>\n"
"\n" "\n"
" <!-- Bracket Matching -->\n" " <!-- Bracket Matching -->\n"
" <style name=\"bracket-match\" foreground=\"white\" background=\"gray\" bold=\"true\"/>\n" " <style name=\"bracket-match\" foreground=\"white\" background=\"gray\" bold=\"true\"/>\n"
@ -194,10 +203,11 @@ const std::string juci_dark_style =
" <color name=\"purple\" value=\"#DD88DD\"/>\n" " <color name=\"purple\" value=\"#DD88DD\"/>\n"
"\n" "\n"
" <style name=\"text\" foreground=\"white\" background=\"black\"/>\n" " <style name=\"text\" foreground=\"white\" background=\"black\"/>\n"
" <style name=\"background-pattern\" background=\"#rgba(255,255,255,.04)\"/>\n"
" <style name=\"selection\" background=\"#215D9C\"/>\n" " <style name=\"selection\" background=\"#215D9C\"/>\n"
"\n" "\n"
" <!-- Current Line Highlighting -->\n" " <!-- Current Line Highlighting -->\n"
" <style name=\"current-line\" background=\"#333333\"/>\n" " <style name=\"current-line\" background=\"#rgba(255,255,255,.06)\"/>\n"
"\n" "\n"
" <!-- Bracket Matching -->\n" " <!-- Bracket Matching -->\n"
" <style name=\"bracket-match\" foreground=\"black\" background=\"gray\" bold=\"true\"/>\n" " <style name=\"bracket-match\" foreground=\"black\" background=\"gray\" bold=\"true\"/>\n"
@ -252,10 +262,11 @@ const std::string juci_dark_blue_style =
" <color name=\"light-green\" value=\"#A0DB6B\"/>\n" " <color name=\"light-green\" value=\"#A0DB6B\"/>\n"
"\n" "\n"
" <style name=\"text\" foreground=\"white\" background=\"dark-blue\"/>\n" " <style name=\"text\" foreground=\"white\" background=\"dark-blue\"/>\n"
" <style name=\"background-pattern\" background=\"#rgba(255,255,255,.04)\"/>\n"
" <style name=\"selection\" background=\"#215D9C\"/>\n" " <style name=\"selection\" background=\"#215D9C\"/>\n"
"\n" "\n"
" <!-- Current Line Highlighting -->\n" " <!-- Current Line Highlighting -->\n"
" <style name=\"current-line\" background=\"blue\"/>\n" " <style name=\"current-line\" background=\"#rgba(255,255,255,.05)\"/>\n"
"\n" "\n"
" <!-- Bracket Matching -->\n" " <!-- Bracket Matching -->\n"
" <style name=\"bracket-match\" foreground=\"dark-blue\" background=\"gray\" bold=\"true\"/>\n" " <style name=\"bracket-match\" foreground=\"dark-blue\" background=\"gray\" bold=\"true\"/>\n"

24
src/juci.cc

@ -58,7 +58,7 @@ void app::on_activate() {
} }
std::thread another_juci_app([this, directory, files_in_directory](){ std::thread another_juci_app([this, directory, files_in_directory](){
Singleton::terminal()->async_print("Executing: juci "+directory.string()+files_in_directory); Singleton::terminal()->async_print("Executing: juci "+directory.string()+files_in_directory);
Singleton::terminal()->execute("juci "+directory.string()+files_in_directory, ""); //TODO: do not open pipes here, doing this after Juci compiles on Windows Singleton::terminal()->execute("juci "+directory.string()+files_in_directory, "", false);
}); });
another_juci_app.detach(); another_juci_app.detach();
} }
@ -67,8 +67,30 @@ void app::on_activate() {
Singleton::window()->notebook.open(file); Singleton::window()->notebook.open(file);
} }
void app::on_startup() {
Gtk::Application::on_startup();
Singleton::menu()->init();
Singleton::menu()->build();
auto object = Singleton::menu()->builder->get_object("juci-menu");
auto juci_menu = Glib::RefPtr<Gio::Menu>::cast_dynamic(object);
object = Singleton::menu()->builder->get_object("window-menu");
auto window_menu = Glib::RefPtr<Gio::Menu>::cast_dynamic(object);
if (!juci_menu || !window_menu) {
std::cerr << "Menu not found." << std::endl;
}
else {
set_app_menu(juci_menu);
set_menubar(window_menu);
}
}
app::app() : Gtk::Application("no.sout.juci", Gio::APPLICATION_NON_UNIQUE | Gio::APPLICATION_HANDLES_COMMAND_LINE) { app::app() : Gtk::Application("no.sout.juci", Gio::APPLICATION_NON_UNIQUE | Gio::APPLICATION_HANDLES_COMMAND_LINE) {
init_logging(); init_logging();
Glib::set_application_name("juCi++");
Singleton::menu()->application=static_cast<Gtk::Application*>(this); //For Ubuntu 14...
Singleton::window();
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {

1
src/juci.h

@ -9,6 +9,7 @@ class app : public Gtk::Application {
app(); app();
int on_command_line(const Glib::RefPtr<Gio::ApplicationCommandLine> &cmd); int on_command_line(const Glib::RefPtr<Gio::ApplicationCommandLine> &cmd);
void on_activate(); void on_activate();
void on_startup();
private: private:
std::vector<boost::filesystem::path> directories; std::vector<boost::filesystem::path> directories;

396
src/menu.cc

@ -1,106 +1,322 @@
#include "menu.h" #include "menu.h"
#include "singletons.h"
#include <string>
#include <iostream> #include <iostream>
using namespace std; //TODO: remove
Menu::Menu() { Menu::Menu() {
action_group = Gtk::ActionGroup::create(); }
ui_manager = Gtk::UIManager::create();
ui_manager->insert_action_group(action_group); //TODO: if Ubuntu ever gets fixed, move to constructor, also cleanup the rest of the Ubuntu specific code
void Menu::init() {
action_group->add(Gtk::Action::create("FileMenu", "File")); auto accels=Singleton::Config::menu()->keys;
action_group->add(Gtk::Action::create("EditMenu", "Edit")); for(auto &accel: accels) {
action_group->add(Gtk::Action::create("WindowMenu", "_Window")); #ifdef UBUNTU_BUGGED_MENU
action_group->add(Gtk::Action::create("ProjectMenu", "P_roject")); size_t pos=0;
action_group->add(Gtk::Action::create("SourceMenu", "_Source")); std::string second=accel.second;
action_group->add(Gtk::Action::create("PluginMenu", "_Plugins")); while((pos=second.find('<', pos))!=std::string::npos) {
action_group->add(Gtk::Action::create("HelpMenu", "Help")); second.replace(pos, 1, "&lt;");
pos+=4;
}
pos=0;
while((pos=second.find('>', pos))!=std::string::npos) {
second.replace(pos, 1, "&gt;");
pos+=4;
}
if(second.size()>0)
accel.second="<attribute name='accel'>"+second+"</attribute>";
else
accel.second="";
#else
accel.second="";
#endif
}
ui_xml = ui_xml =
"<ui>\n" "<interface>"
" <menubar name=\"MenuBar\">\n" " <menu id='juci-menu'>"
" <menu action=\"FileMenu\">\n" " <section>"
" <menuitem action=\"FileNewFile\"/>\n" " <item>"
" <menuitem action=\"FileNewFolder\"/>\n" " <attribute name='label' translatable='yes'>_About</attribute>"
" <menu action=\"FileNewProject\">\n" " <attribute name='action'>app.about</attribute>"
" <menuitem action=\"FileNewProjectCpp\"/>\n" +accels["about"]+ //For Ubuntu...
" </menu>\n" " </item>"
" <separator/>\n" " </section>"
" <menuitem action=\"FileOpenFile\"/>\n" " <section>"
" <menuitem action=\"FileOpenFolder\"/>\n" " <item>"
" <separator/>\n" " <attribute name='label' translatable='yes'>_Preferences</attribute>"
" <menuitem action=\"FileSave\"/>\n" " <attribute name='action'>app.preferences</attribute>"
" <menuitem action=\"FileSaveAs\"/>\n" +accels["preferences"]+ //For Ubuntu...
" <separator/>\n" " </item>"
" <menuitem action=\"Preferences\"/>\n" " </section>"
" <separator/>\n" " <section>"
" <menuitem action=\"FileQuit\"/>\n" " <item>"
" </menu>\n" " <attribute name='label' translatable='yes'>_Quit</attribute>"
" <menu action=\"EditMenu\">\n" " <attribute name='action'>app.quit</attribute>"
" <menuitem action=\"EditUndo\"/>\n" +accels["quit"]+ //For Ubuntu...
" <menuitem action=\"EditRedo\"/>\n" " </item>"
" <separator/>\n" " </section>"
" <menuitem action=\"EditCopy\"/>\n" " </menu>"
" <menuitem action=\"EditCut\"/>\n" ""
" <menuitem action=\"EditPaste\"/>\n" " <menu id='window-menu'>"
" <separator/>\n" " <submenu>"
" <menuitem action=\"EditFind\"/>\n" " <attribute name='label' translatable='yes'>_File</attribute>"
" </menu>\n" " <section>"
" <menu action=\"SourceMenu\">\n" " <item>"
" <menu action=\"SourceSpellCheck\">\n" " <attribute name='label' translatable='yes'>_New _File</attribute>"
" <menuitem action=\"SourceSpellCheckBuffer\"/>\n" " <attribute name='action'>app.new_file</attribute>"
" <menuitem action=\"SourceSpellCheckClear\"/>\n" +accels["new_file"]+ //For Ubuntu...
" <menuitem action=\"SourceSpellCheckNextError\"/>\n" " </item>"
" </menu>\n" " <item>"
" <separator/>\n" " <attribute name='label' translatable='yes'>_New _Directory</attribute>"
" <menu action=\"SourceIndentation\">\n" " <attribute name='action'>app.new_folder</attribute>"
" <menuitem action=\"SourceIndentationSetBufferTab\"/>\n" +accels["new_folder"]+ //For Ubuntu...
" <menuitem action=\"SourceIndentationAutoIndentBuffer\"/>\n" " </item>"
" </menu>\n" " <submenu>"
" <separator/>\n" " <attribute name='label' translatable='yes'>_New _Project</attribute>"
" <menuitem action=\"SourceGotoLine\"/>\n" " <item>"
" <menuitem action=\"SourceCenterCursor\"/>\n" " <attribute name='label' translatable='no'>C++</attribute>"
" <separator/>\n" " <attribute name='action'>app.new_project_cpp</attribute>"
" <menuitem action=\"SourceFindDocumentation\"/>\n" +accels["new_project_cpp"]+ //For Ubuntu...
" <separator/>\n" " </item>"
" <menuitem action=\"SourceGotoDeclaration\"/>\n" " </submenu>"
" <menuitem action=\"SourceGotoMethod\"/>\n" " </section>"
" <menuitem action=\"SourceRename\"/>\n" " <section>"
" <separator/>\n" " <item>"
" <menuitem action=\"SourceGotoNextDiagnostic\"/>\n" " <attribute name='label' translatable='yes'>_Open _File</attribute>"
" <menuitem action=\"SourceApplyFixIts\"/>\n" " <attribute name='action'>app.open_file</attribute>"
" <separator/>\n" +accels["open_file"]+ //For Ubuntu...
" </menu>\n" " </item>"
" <menu action=\"ProjectMenu\">\n" " <item>"
" <menuitem action=\"ProjectCompileAndRun\"/>\n" " <attribute name='label' translatable='yes'>_Open _Folder</attribute>"
" <menuitem action=\"ProjectCompile\"/>\n" " <attribute name='action'>app.open_folder</attribute>"
" <separator/>\n" +accels["open_folder"]+ //For Ubuntu...
" <menuitem action=\"ProjectRunCommand\"/>\n" " </item>"
" <menuitem action=\"ProjectKillLastRunning\"/>\n" " </section>"
" <menuitem action=\"ProjectForceKillLastRunning\"/>\n" " <section>"
" </menu>\n" " <item>"
" <menu action=\"WindowMenu\">\n" " <attribute name='label' translatable='yes'>_Save</attribute>"
" <menuitem action=\"WindowNextTab\"/>\n" " <attribute name='action'>app.save</attribute>"
" <menuitem action=\"WindowPreviousTab\"/>\n" +accels["save"]+ //For Ubuntu...
" <separator/>\n" " </item>"
" <menuitem action=\"WindowCloseTab\"/>\n" " <item>"
" </menu>\n" " <attribute name='label' translatable='yes'>_Save _As</attribute>"
" <menu action=\"PluginMenu\">\n" " <attribute name='action'>app.save_as</attribute>"
" </menu>\n" +accels["save_as"]+ //For Ubuntu...
" <menu action=\"HelpMenu\">\n" " </item>"
" <menuitem action=\"HelpAbout\"/>\n" " </section>"
" </menu>\n" " </submenu>"
" </menubar>\n" ""
"</ui>\n"; " <submenu>"
" <attribute name='label' translatable='yes'>_Edit</attribute>"
" <section>"
" <item>"
" <attribute name='label' translatable='yes'>_Undo</attribute>"
" <attribute name='action'>app.edit_undo</attribute>"
+accels["edit_undo"]+ //For Ubuntu...
" </item>"
" <item>"
" <attribute name='label' translatable='yes'>_Redo</attribute>"
" <attribute name='action'>app.edit_redo</attribute>"
+accels["edit_redo"]+ //For Ubuntu...
" </item>"
" </section>"
" <section>"
" <item>"
" <attribute name='label' translatable='yes'>_Cut</attribute>"
" <attribute name='action'>app.edit_cut</attribute>"
+accels["edit_cut"]+ //For Ubuntu...
" </item>"
" <item>"
" <attribute name='label' translatable='yes'>_Copy</attribute>"
" <attribute name='action'>app.edit_copy</attribute>"
+accels["edit_copy"]+ //For Ubuntu...
" </item>"
" <item>"
" <attribute name='label' translatable='yes'>_Paste</attribute>"
" <attribute name='action'>app.edit_paste</attribute>"
+accels["edit_paste"]+ //For Ubuntu...
" </item>"
" </section>"
" <section>"
" <item>"
" <attribute name='label' translatable='yes'>_Find</attribute>"
" <attribute name='action'>app.edit_find</attribute>"
+accels["edit_find"]+ //For Ubuntu...
" </item>"
" </section>"
" </submenu>"
""
" <submenu>"
" <attribute name='label' translatable='yes'>_Source</attribute>"
" <section>"
" <submenu>"
" <attribute name='label' translatable='yes'>_Spell _Check</attribute>"
" <item>"
" <attribute name='label' translatable='yes'>_Spell _Check _Buffer</attribute>"
" <attribute name='action'>app.source_spellcheck</attribute>"
+accels["source_spellcheck"]+ //For Ubuntu...
" </item>"
" <item>"
" <attribute name='label' translatable='yes'>_Clear _Spelling _Errors</attribute>"
" <attribute name='action'>app.source_spellcheck_clear</attribute>"
+accels["source_spellcheck_clear"]+ //For Ubuntu...
" </item>"
" <item>"
" <attribute name='label' translatable='yes'>_Go _to _Next _Spelling _Error</attribute>"
" <attribute name='action'>app.source_spellcheck_next_error</attribute>"
+accels["source_spellcheck_next_error"]+ //For Ubuntu...
" </item>"
" </submenu>"
" </section>"
" <section>"
" <submenu>"
" <attribute name='label' translatable='yes'>_Indentation</attribute>"
" <item>"
" <attribute name='label' translatable='yes'>_Set _Current _Buffer _Tab</attribute>"
" <attribute name='action'>app.source_indentation_set_buffer_tab</attribute>"
+accels["source_indentation_set_buffer_tab"]+ //For Ubuntu...
" </item>"
" <item>"
" <attribute name='label' translatable='yes'>_Auto-Indent _Current _Buffer</attribute>"
" <attribute name='action'>app.source_indentation_auto_indent_buffer</attribute>"
+accels["source_indentation_auto_indent_buffer"]+ //For Ubuntu...
" </item>"
" </submenu>"
" </section>"
" <section>"
" <item>"
" <attribute name='label' translatable='yes'>_Go _to _Line</attribute>"
" <attribute name='action'>app.source_goto_line</attribute>"
+accels["source_goto_line"]+ //For Ubuntu...
" </item>"
" <item>"
" <attribute name='label' translatable='yes'>_Center _Cursor</attribute>"
" <attribute name='action'>app.source_center_cursor</attribute>"
+accels["source_center_cursor"]+ //For Ubuntu...
" </item>"
" </section>"
" <section>"
" <item>"
" <attribute name='label' translatable='yes'>_Find _Documentation</attribute>"
" <attribute name='action'>app.source_find_documentation</attribute>"
+accels["source_find_documentation"]+ //For Ubuntu...
" </item>"
" </section>"
" <section>"
" <item>"
" <attribute name='label' translatable='yes'>_Go to Declaration</attribute>"
" <attribute name='action'>app.source_goto_declaration</attribute>"
+accels["source_goto_declaration"]+ //For Ubuntu...
" </item>"
" <item>"
" <attribute name='label' translatable='yes'>_Go to Method</attribute>"
" <attribute name='action'>app.source_goto_method</attribute>"
+accels["source_goto_method"]+ //For Ubuntu...
" </item>"
" <item>"
" <attribute name='label' translatable='yes'>_Rename</attribute>"
" <attribute name='action'>app.source_rename</attribute>"
+accels["source_rename"]+ //For Ubuntu...
" </item>"
" </section>"
" <section>"
" <item>"
" <attribute name='label' translatable='yes'>_Go to Next Diagnostic</attribute>"
" <attribute name='action'>app.source_goto_next_diagnostic</attribute>"
+accels["source_goto_next_diagnostic"]+ //For Ubuntu...
" </item>"
" <item>"
" <attribute name='label' translatable='yes'>_Apply Fix-Its</attribute>"
" <attribute name='action'>app.source_apply_fix_its</attribute>"
+accels["source_apply_fix_its"]+ //For Ubuntu...
" </item>"
" </section>"
" </submenu>"
""
" <submenu>"
" <attribute name='label' translatable='yes'>_Project</attribute>"
" <section>"
" <item>"
" <attribute name='label' translatable='yes'>_Compile _and _Run</attribute>"
" <attribute name='action'>app.compile_and_run</attribute>"
+accels["compile_and_run"]+ //For Ubuntu...
" </item>"
" <item>"
" <attribute name='label' translatable='yes'>_Compile</attribute>"
" <attribute name='action'>app.compile</attribute>"
+accels["compile"]+ //For Ubuntu...
" </item>"
" </section>"
" <section>"
" <item>"
" <attribute name='label' translatable='yes'>_Run _Command</attribute>"
" <attribute name='action'>app.run_command</attribute>"
+accels["run_command"]+ //For Ubuntu...
" </item>"
" <item>"
" <attribute name='label' translatable='yes'>_Kill _Last _Process</attribute>"
" <attribute name='action'>app.kill_last_running</attribute>"
+accels["kill_last_running"]+ //For Ubuntu...
" </item>"
" <item>"
" <attribute name='label' translatable='yes'>_Force _Kill _Last _Process</attribute>"
" <attribute name='action'>app.force_kill_last_running</attribute>"
+accels["force_kill_last_running"]+ //For Ubuntu...
" </item>"
" </section>"
" </submenu>"
""
" <submenu>"
" <attribute name='label' translatable='yes'>_Window</attribute>"
" <section>"
" <item>"
" <attribute name='label' translatable='yes'>_Next _Tab</attribute>"
" <attribute name='action'>app.next_tab</attribute>"
+accels["next_tab"]+ //For Ubuntu...
" </item>"
" <item>"
" <attribute name='label' translatable='yes'>_Previous _Tab</attribute>"
" <attribute name='action'>app.previous_tab</attribute>"
+accels["previous_tab"]+ //For Ubuntu...
" </item>"
" </section>"
" <section>"
" <item>"
" <attribute name='label' translatable='yes'>_Close _Tab</attribute>"
" <attribute name='action'>app.close_tab</attribute>"
+accels["close_tab"]+ //For Ubuntu...
" </item>"
" </section>"
" </submenu>"
" </menu>"
"</interface>";
} }
Gtk::Widget& Menu::get_widget() { void Menu::add_action(const std::string &name, std::function<void()> action) {
return *ui_manager->get_widget("/MenuBar"); actions[name]=application->add_action(name, action);
}
void Menu::set_keys() {
for(auto &key: Singleton::Config::menu()->keys) {
if(key.second.size()>0 && actions.find(key.first)!=actions.end()) {
#if GTK_VERSION_GE(3, 12)
application->set_accel_for_action("app."+key.first, key.second);
#else
application->add_accelerator(key.second, "app."+key.first); //For Ubuntu 14...
#endif
}
}
} }
void Menu::build() { void Menu::build() {
builder = Gtk::Builder::create();
try { try {
ui_manager->add_ui_from_string(ui_xml); builder->add_from_string(ui_xml);
} }
catch (const Glib::Error &ex) { catch (const Glib::Error &ex) {
std::cerr << "building menu failed" << ex.what(); std::cerr << "building menu failed: " << ex.what();
} }
} }

17
src/menu.h

@ -7,13 +7,22 @@
class Menu { class Menu {
public: public:
class Config {
public:
std::unordered_map<std::string, std::string> keys;
};
Menu(); Menu();
Gtk::Widget& get_widget(); void init(); //For Ubuntu 14...
Gtk::Application* application; //For Ubuntu 14...
void add_action(const std::string &name, std::function<void()> action);
std::unordered_map<std::string, Glib::RefPtr<Gio::SimpleAction> > actions;
void set_keys();
void build(); void build();
Glib::RefPtr<Gtk::Builder> builder;
std::unordered_map<std::string, std::string> key_map;
std::string ui_xml; std::string ui_xml;
Glib::RefPtr<Gtk::UIManager> ui_manager;
Glib::RefPtr<Gtk::ActionGroup> action_group;
}; };
#endif // JUCI_MENU_H_ #endif // JUCI_MENU_H_

25
src/notebook.cc

@ -5,7 +5,7 @@
#include <regex> #include <regex>
#include "cmake.h" #include "cmake.h"
#if GTK_VERSION_GE(3, 18) #if GTKSOURCEVIEWMM_MAJOR_VERSION > 2 & GTKSOURCEVIEWMM_MINOR_VERSION > 17
#include "gtksourceview-3.0/gtksourceview/gtksourcemap.h" #include "gtksourceview-3.0/gtksourceview/gtksourcemap.h"
#endif #endif
@ -26,8 +26,12 @@ namespace sigc {
#endif #endif
} }
Notebook::Notebook() : Gtk::Notebook() { Notebook::Notebook() : Gtk::Notebook(), last_index(-1) {
Gsv::init(); Gsv::init();
signal_switch_page().connect([this](Gtk::Widget* page, guint page_num) {
last_index=-1;
});
} }
int Notebook::size() { int Notebook::size() {
@ -102,7 +106,7 @@ void Notebook::open(const boost::filesystem::path &file_path) {
scrolled_windows.back()->add(*source_views.back()); scrolled_windows.back()->add(*source_views.back());
hboxes.back()->pack_start(*scrolled_windows.back()); hboxes.back()->pack_start(*scrolled_windows.back());
#if GTK_VERSION_GE(3, 18) #if GTKSOURCEVIEWMM_MAJOR_VERSION > 2 & GTKSOURCEVIEWMM_MINOR_VERSION > 17
source_maps.emplace_back(Glib::wrap(gtk_source_map_new())); source_maps.emplace_back(Glib::wrap(gtk_source_map_new()));
gtk_source_map_set_view(GTK_SOURCE_MAP(source_maps.back()->gobj()), source_views.back()->gobj()); gtk_source_map_set_view(GTK_SOURCE_MAP(source_maps.back()->gobj()), source_views.back()->gobj());
#endif #endif
@ -113,7 +117,13 @@ void Notebook::open(const boost::filesystem::path &file_path) {
set_tab_reorderable(*hboxes.back(), true); set_tab_reorderable(*hboxes.back(), true);
show_all_children(); show_all_children();
size_t last_index_tmp=-1;
if(get_current_page()!=-1)
last_index_tmp=get_index(get_current_page());
set_current_page(size()-1); set_current_page(size()-1);
last_index=last_index_tmp;
set_focus_child(*source_views.back()); set_focus_child(*source_views.back());
get_current_view()->get_buffer()->set_modified(false); get_current_view()->get_buffer()->set_modified(false);
get_current_view()->grab_focus(); get_current_view()->grab_focus();
@ -138,7 +148,7 @@ void Notebook::open(const boost::filesystem::path &file_path) {
} }
void Notebook::configure(int view_nr) { void Notebook::configure(int view_nr) {
#if GTK_VERSION_GE(3, 18) #if GTKSOURCEVIEWMM_MAJOR_VERSION > 2 & GTKSOURCEVIEWMM_MINOR_VERSION > 17
auto source_font_description=Pango::FontDescription(Singleton::Config::source()->font); auto source_font_description=Pango::FontDescription(Singleton::Config::source()->font);
auto source_map_font_desc=Pango::FontDescription(static_cast<std::string>(source_font_description.get_family())+" "+Singleton::Config::source()->map_font_size); auto source_map_font_desc=Pango::FontDescription(static_cast<std::string>(source_font_description.get_family())+" "+Singleton::Config::source()->map_font_size);
source_maps.at(view_nr)->override_font(source_map_font_desc); source_maps.at(view_nr)->override_font(source_map_font_desc);
@ -228,8 +238,13 @@ bool Notebook::close_current_page() {
} }
int page = get_current_page(); int page = get_current_page();
int index=get_index(page); int index=get_index(page);
if(last_index!=static_cast<size_t>(-1)) {
set_current_page(page_num(*hboxes.at(last_index)));
last_index=-1;
}
remove_page(page); remove_page(page);
#if GTK_VERSION_GE(3, 18) #if GTKSOURCEVIEWMM_MAJOR_VERSION > 2 & GTKSOURCEVIEWMM_MINOR_VERSION > 17
source_maps.erase(source_maps.begin()+index); source_maps.erase(source_maps.begin()+index);
#endif #endif
auto source_view=source_views.at(index); auto source_view=source_views.at(index);

2
src/notebook.h

@ -29,5 +29,7 @@ private:
std::vector<std::unique_ptr<Gtk::Widget> > source_maps; std::vector<std::unique_ptr<Gtk::Widget> > source_maps;
std::vector<std::unique_ptr<Gtk::ScrolledWindow> > scrolled_windows; std::vector<std::unique_ptr<Gtk::ScrolledWindow> > scrolled_windows;
std::vector<std::unique_ptr<Gtk::HBox> > hboxes; std::vector<std::unique_ptr<Gtk::HBox> > hboxes;
size_t last_index;
}; };
#endif // JUCI_NOTEBOOK_H_ #endif // JUCI_NOTEBOOK_H_

16
src/singletons.cc

@ -4,23 +4,26 @@ std::unique_ptr<Source::Config> Singleton::Config::source_=std::unique_ptr<Sourc
std::unique_ptr<Directories::Config> Singleton::Config::directories_=std::unique_ptr<Directories::Config>(new Directories::Config()); std::unique_ptr<Directories::Config> Singleton::Config::directories_=std::unique_ptr<Directories::Config>(new Directories::Config());
std::unique_ptr<Terminal::Config> Singleton::Config::terminal_=std::unique_ptr<Terminal::Config>(new Terminal::Config()); std::unique_ptr<Terminal::Config> Singleton::Config::terminal_=std::unique_ptr<Terminal::Config>(new Terminal::Config());
std::unique_ptr<Window::Config> Singleton::Config::window_ = std::unique_ptr<Window::Config>(new Window::Config()); std::unique_ptr<Window::Config> Singleton::Config::window_ = std::unique_ptr<Window::Config>(new Window::Config());
std::unique_ptr<Terminal> Singleton::terminal_=std::unique_ptr<Terminal>();
std::unique_ptr<Directories> Singleton::directories_=std::unique_ptr<Directories>();
std::unique_ptr<Window> Singleton::window_=std::unique_ptr<Window>();
std::unique_ptr<MainConfig> Singleton::Config::main_=std::unique_ptr<MainConfig>(new MainConfig()); std::unique_ptr<MainConfig> Singleton::Config::main_=std::unique_ptr<MainConfig>(new MainConfig());
std::unique_ptr<Menu::Config> Singleton::Config::menu_ = std::unique_ptr<Menu::Config>(new Menu::Config());
std::unique_ptr<Terminal> Singleton::terminal_=std::unique_ptr<Terminal>();
Terminal *Singleton::terminal() { Terminal *Singleton::terminal() {
if(!terminal_) if(!terminal_)
terminal_=std::unique_ptr<Terminal>(new Terminal()); terminal_=std::unique_ptr<Terminal>(new Terminal());
return terminal_.get(); return terminal_.get();
} }
std::unique_ptr<Directories> Singleton::directories_=std::unique_ptr<Directories>();
Directories *Singleton::directories() { Directories *Singleton::directories() {
if(!directories_) if(!directories_)
directories_=std::unique_ptr<Directories>(new Directories()); directories_=std::unique_ptr<Directories>(new Directories());
return directories_.get(); return directories_.get();
} }
std::unique_ptr<Window> Singleton::window_=std::unique_ptr<Window>();
Window *Singleton::window() { Window *Singleton::window() {
if(!window_) if(!window_)
window_=std::unique_ptr<Window>(new Window()); window_=std::unique_ptr<Window>(new Window());
@ -33,6 +36,7 @@ Gtk::Label *Singleton::status() {
status_=std::unique_ptr<Gtk::Label>(new Gtk::Label()); status_=std::unique_ptr<Gtk::Label>(new Gtk::Label());
return status_.get(); return status_.get();
} }
std::unique_ptr<Gtk::Label> Singleton::info_=std::unique_ptr<Gtk::Label>(); std::unique_ptr<Gtk::Label> Singleton::info_=std::unique_ptr<Gtk::Label>();
Gtk::Label *Singleton::info() { Gtk::Label *Singleton::info() {
if(!info_) if(!info_)
@ -40,3 +44,9 @@ Gtk::Label *Singleton::info() {
return info_.get(); return info_.get();
} }
std::unique_ptr<Menu> Singleton::menu_=std::unique_ptr<Menu>();
Menu *Singleton::menu() {
if(!menu_)
menu_=std::unique_ptr<Menu>(new Menu());
return menu_.get();
}

4
src/singletons.h

@ -21,6 +21,7 @@ public:
static Directories::Config *directories() {return directories_.get();} static Directories::Config *directories() {return directories_.get();}
static Window::Config *window() { return window_.get(); } static Window::Config *window() { return window_.get(); }
static Terminal::Config *terminal() {return terminal_.get();} static Terminal::Config *terminal() {return terminal_.get();}
static Menu::Config *menu() {return menu_.get();}
static MainConfig *main() { return main_.get(); } static MainConfig *main() { return main_.get(); }
private: private:
@ -28,12 +29,14 @@ public:
static std::unique_ptr<Window::Config> window_; static std::unique_ptr<Window::Config> window_;
static std::unique_ptr<Directories::Config> directories_; static std::unique_ptr<Directories::Config> directories_;
static std::unique_ptr<Terminal::Config> terminal_; static std::unique_ptr<Terminal::Config> terminal_;
static std::unique_ptr<Menu::Config> menu_;
static std::unique_ptr<MainConfig> main_; static std::unique_ptr<MainConfig> main_;
}; };
static Terminal *terminal(); static Terminal *terminal();
static Directories *directories(); static Directories *directories();
static Gtk::Label *status(); static Gtk::Label *status();
static Gtk::Label *info(); static Gtk::Label *info();
static Menu *menu();
static Window *window(); static Window *window();
private: private:
@ -41,6 +44,7 @@ private:
static std::unique_ptr<Gtk::Label> status_; static std::unique_ptr<Gtk::Label> status_;
static std::unique_ptr<Gtk::Label> info_; static std::unique_ptr<Gtk::Label> info_;
static std::unique_ptr<Directories> directories_; static std::unique_ptr<Directories> directories_;
static std::unique_ptr<Menu> menu_;
static std::unique_ptr<Window> window_; static std::unique_ptr<Window> window_;
}; };

33
src/source.cc

@ -314,6 +314,9 @@ void Source::View::configure() {
property_show_line_numbers() = Singleton::Config::source()->show_line_numbers; property_show_line_numbers() = Singleton::Config::source()->show_line_numbers;
if(Singleton::Config::source()->font.size()>0) if(Singleton::Config::source()->font.size()>0)
override_font(Pango::FontDescription(Singleton::Config::source()->font)); override_font(Pango::FontDescription(Singleton::Config::source()->font));
#if GTKSOURCEVIEWMM_MAJOR_VERSION > 2 & GTKSOURCEVIEWMM_MINOR_VERSION > 15
gtk_source_view_set_background_pattern(this->gobj(), GTK_SOURCE_BACKGROUND_PATTERN_TYPE_GRID);
#endif
//Create tags for diagnostic warnings and errors: //Create tags for diagnostic warnings and errors:
auto scheme = get_source_buffer()->get_style_scheme(); auto scheme = get_source_buffer()->get_style_scheme();
@ -350,11 +353,9 @@ void Source::View::configure() {
error_property=style->property_background().get_value(); error_property=style->property_background().get_value();
diagnostic_tag_underline->property_underline()=Pango::Underline::UNDERLINE_ERROR; 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: #if GTK_VERSION_GE(3, 16)
auto param_spec=g_object_class_find_property(tag_class, "underline-rgba"); diagnostic_tag_underline->set_property("underline-rgba", Gdk::RGBA(error_property));
if(param_spec!=NULL) { #endif
diagnostic_tag_underline->set_property("underline-rgba", Gdk::RGBA(error_property));
}
} }
//TODO: clear tag_class and param_spec? //TODO: clear tag_class and param_spec?
@ -1021,21 +1022,19 @@ bool Source::View::on_key_press_event(GdkEventKey* key) {
auto line_it = get_source_buffer()->get_iter_at_line(line_nr); auto line_it = get_source_buffer()->get_iter_at_line(line_nr);
if(!get_buffer()->get_has_selection() || line_it!=selection_end) { if(!get_buffer()->get_has_selection() || line_it!=selection_end) {
auto tabs_end_iter=get_tabs_end_iter(line_nr); auto tabs_end_iter=get_tabs_end_iter(line_nr);
auto line_tabs=get_line_before(tabs_end_iter); if(tabs_end_iter.starts_line() && tabs_end_iter.ends_line())
ignore_line.push_back(true);
if(line_tabs.size()>0 || tabs_end_iter.ends_line()) { else {
if(!tabs_end_iter.ends_line()) { auto line_tabs=get_line_before(tabs_end_iter);
if(line_tabs.size()>0) {
indent_left_steps=std::min(indent_left_steps, static_cast<unsigned>(line_tabs.size())); indent_left_steps=std::min(indent_left_steps, static_cast<unsigned>(line_tabs.size()));
ignore_line.push_back(false); ignore_line.push_back(false);
} }
else if(static_cast<unsigned>(line_tabs.size())<indent_left_steps) else {
ignore_line.push_back(true); get_source_buffer()->end_user_action();
else return true;
ignore_line.push_back(false); }
}
else {
get_source_buffer()->end_user_action();
return true;
} }
} }
} }

2
src/source.h

@ -36,6 +36,7 @@ namespace Source {
bool highlight_current_line; bool highlight_current_line;
bool show_line_numbers; bool show_line_numbers;
std::unordered_map<std::string, std::string> clang_types; std::unordered_map<std::string, std::string> clang_types;
std::string clang_format_style;
std::unordered_map<std::string, DocumentationSearch> documentation_searches; std::unordered_map<std::string, DocumentationSearch> documentation_searches;
}; };
@ -100,6 +101,7 @@ namespace Source {
boost::filesystem::path project_path; boost::filesystem::path project_path;
Glib::RefPtr<Gsv::Language> language; Glib::RefPtr<Gsv::Language> language;
std::function<void()> auto_indent;
std::function<std::pair<std::string, Offset>()> get_declaration_location; std::function<std::pair<std::string, Offset>()> get_declaration_location;
std::function<void()> goto_method; std::function<void()> goto_method;
std::function<Token()> get_token; std::function<Token()> get_token;

80
src/source_clang.cc

@ -35,7 +35,7 @@ Source::View(file_path, project_path, language), parse_error(false) {
parsing_in_progress=Singleton::terminal()->print_in_progress("Parsing "+file_path.string()); parsing_in_progress=Singleton::terminal()->print_in_progress("Parsing "+file_path.string());
//GTK-calls must happen in main thread, so the parse_thread //GTK-calls must happen in main thread, so the parse_thread
//sends signals to the main thread that it is to call the following functions: //sends signals to the main thread that it is to call the following functions:
parse_start.connect([this]{ parse_start_connection=parse_start.connect([this]{
if(parse_thread_buffer_map_mutex.try_lock()) { if(parse_thread_buffer_map_mutex.try_lock()) {
parse_thread_buffer_map=get_buffer_map(); parse_thread_buffer_map=get_buffer_map();
parse_thread_mapped=true; parse_thread_mapped=true;
@ -43,7 +43,7 @@ Source::View(file_path, project_path, language), parse_error(false) {
} }
parse_thread_go=true; parse_thread_go=true;
}); });
parse_done.connect([this](){ parse_done_connection=parse_done.connect([this](){
if(parse_thread_mapped) { if(parse_thread_mapped) {
if(parsing_mutex.try_lock()) { if(parsing_mutex.try_lock()) {
update_syntax(); update_syntax();
@ -58,7 +58,7 @@ Source::View(file_path, project_path, language), parse_error(false) {
parse_thread_go=true; parse_thread_go=true;
} }
}); });
parse_fail.connect([this](){ parse_fail_connection=parse_fail.connect([this](){
Singleton::terminal()->print("Error: failed to reparse "+this->file_path.string()+".\n"); Singleton::terminal()->print("Error: failed to reparse "+this->file_path.string()+".\n");
set_status(""); set_status("");
set_info(""); set_info("");
@ -105,10 +105,6 @@ void Source::ClangViewParse::configure() {
no_bracket_no_para_statement_regex=std::regex("^([ \\t]*)(else|try|do) *$"); no_bracket_no_para_statement_regex=std::regex("^([ \\t]*)(else|try|do) *$");
} }
Source::ClangViewParse::~ClangViewParse() {
delayed_reparse_connection.disconnect();
}
void Source::ClangViewParse::init_parse() { void Source::ClangViewParse::init_parse() {
type_tooltips.hide(); type_tooltips.hide();
diagnostic_tooltips.hide(); diagnostic_tooltips.hide();
@ -659,9 +655,10 @@ Source::ClangViewParse(file_path, project_path, language), autocomplete_cancel_s
autocomplete_cancel_starting=false; autocomplete_cancel_starting=false;
}); });
do_delete_object.connect([this](){ do_delete_object_connection=do_delete_object.connect([this](){
if(delete_thread.joinable()) if(delete_thread.joinable())
delete_thread.join(); delete_thread.join();
do_delete_object_connection.disconnect();
delete this; delete this;
}); });
do_restart_parse.connect([this](){ do_restart_parse.connect([this](){
@ -874,8 +871,6 @@ std::vector<Source::ClangViewAutocomplete::AutoCompleteData> Source::ClangViewAu
void Source::ClangViewAutocomplete::async_delete() { void Source::ClangViewAutocomplete::async_delete() {
parsing_in_progress->cancel("canceled, freeing resources in the background"); parsing_in_progress->cancel("canceled, freeing resources in the background");
autocomplete_done_connection.disconnect();
autocomplete_fail_connection.disconnect();
parse_thread_stop=true; parse_thread_stop=true;
delete_thread=std::thread([this](){ delete_thread=std::thread([this](){
//TODO: Is it possible to stop the clang-process in progress? //TODO: Is it possible to stop the clang-process in progress?
@ -928,6 +923,54 @@ Source::ClangViewAutocomplete(file_path, project_path, language) {
} }
}); });
auto_indent=[this]() {
std::string command="clang-format";
unsigned indent_width;
std::string tab_style;
if(tab_char=='\t') {
indent_width=tab_size*8;
tab_style="UseTab: Always";
}
else {
indent_width=tab_size;
tab_style="UseTab: Never";
}
command+=" -style=\"{IndentWidth: "+std::to_string(indent_width);
command+=", "+tab_style;
command+=", "+std::string("AccessModifierOffset: -")+std::to_string(indent_width);
if(Singleton::Config::source()->clang_format_style!="")
command+=", "+Singleton::Config::source()->clang_format_style;
command+="}\"";
std::stringstream stdin_stream(get_buffer()->get_text()), stdout_stream;
auto exit_code=Singleton::terminal()->execute(stdin_stream, stdout_stream, command);
if(exit_code==0) {
get_source_buffer()->begin_user_action();
auto iter=get_buffer()->get_insert()->get_iter();
auto cursor_line_nr=iter.get_line();
auto cursor_line_offset=iter.get_line_offset();
get_buffer()->erase(get_buffer()->begin(), get_buffer()->end());
get_buffer()->insert(get_buffer()->begin(), stdout_stream.str());
cursor_line_nr=std::min(cursor_line_nr, get_buffer()->get_line_count()-1);
if(cursor_line_nr>=0) {
iter=get_buffer()->get_iter_at_line(cursor_line_nr);
for(int c=0;c<cursor_line_offset;c++) {
if(iter.ends_line())
break;
iter.forward_char();
}
get_buffer()->place_cursor(iter);
while(gtk_events_pending())
gtk_main_iteration();
scroll_to(get_buffer()->get_insert(), 0.0, 1.0, 0.5);
}
get_source_buffer()->end_user_action();
}
};
get_token=[this]() -> Token { get_token=[this]() -> Token {
if(source_readable) { if(source_readable) {
auto iter=get_buffer()->get_insert()->get_iter(); auto iter=get_buffer()->get_insert()->get_iter();
@ -1224,13 +1267,22 @@ void Source::ClangViewRefactor::tag_similar_tokens(const Token &token) {
} }
} }
Source::ClangViewRefactor::~ClangViewRefactor() {
delayed_tag_similar_tokens_connection.disconnect();
}
Source::ClangView::ClangView(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path, Glib::RefPtr<Gsv::Language> language): ClangViewRefactor(file_path, project_path, language) { Source::ClangView::ClangView(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path, Glib::RefPtr<Gsv::Language> language): ClangViewRefactor(file_path, project_path, language) {
if(language) { if(language) {
get_source_buffer()->set_highlight_syntax(true); get_source_buffer()->set_highlight_syntax(true);
get_source_buffer()->set_language(language); get_source_buffer()->set_language(language);
} }
} }
void Source::ClangView::async_delete() {
delayed_reparse_connection.disconnect();
parse_done_connection.disconnect();
parse_start_connection.disconnect();
parse_fail_connection.disconnect();
autocomplete_done_connection.disconnect();
autocomplete_fail_connection.disconnect();
do_restart_parse_connection.disconnect();
delayed_tag_similar_tokens_connection.disconnect();
ClangViewAutocomplete::async_delete();
}

24
src/source_clang.h

@ -21,8 +21,7 @@ namespace Source {
}; };
ClangViewParse(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path, Glib::RefPtr<Gsv::Language> language); ClangViewParse(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path, Glib::RefPtr<Gsv::Language> language);
~ClangViewParse(); virtual void configure();
void configure();
void start_reparse(); void start_reparse();
bool reparse_needed=false; bool reparse_needed=false;
@ -39,8 +38,8 @@ namespace Source {
std::atomic<bool> parse_thread_stop; std::atomic<bool> parse_thread_stop;
std::atomic<bool> parse_error; std::atomic<bool> parse_error;
void show_diagnostic_tooltips(const Gdk::Rectangle &rectangle); virtual void show_diagnostic_tooltips(const Gdk::Rectangle &rectangle);
void show_type_tooltips(const Gdk::Rectangle &rectangle); virtual void show_type_tooltips(const Gdk::Rectangle &rectangle);
std::regex bracket_regex; std::regex bracket_regex;
std::regex no_bracket_statement_regex; std::regex no_bracket_statement_regex;
@ -48,6 +47,10 @@ namespace Source {
std::set<int> diagnostic_offsets; std::set<int> diagnostic_offsets;
std::vector<FixIt> fix_its; std::vector<FixIt> fix_its;
sigc::connection parse_done_connection;
sigc::connection parse_start_connection;
sigc::connection parse_fail_connection;
private: private:
std::map<std::string, std::string> get_buffer_map() const; std::map<std::string, std::string> get_buffer_map() const;
void update_syntax(); void update_syntax();
@ -77,11 +80,15 @@ namespace Source {
}; };
ClangViewAutocomplete(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path, Glib::RefPtr<Gsv::Language> language); ClangViewAutocomplete(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path, Glib::RefPtr<Gsv::Language> language);
void async_delete(); virtual void async_delete();
bool restart_parse(); bool restart_parse();
protected: protected:
bool on_key_press_event(GdkEventKey* key); bool on_key_press_event(GdkEventKey* key);
std::thread autocomplete_thread; std::thread autocomplete_thread;
sigc::connection autocomplete_done_connection;
sigc::connection autocomplete_fail_connection;
sigc::connection do_delete_object_connection;
sigc::connection do_restart_parse_connection;
private: private:
void start_autocomplete(); void start_autocomplete();
void autocomplete(); void autocomplete();
@ -89,9 +96,7 @@ namespace Source {
bool completion_dialog_shown=false; bool completion_dialog_shown=false;
std::vector<AutoCompleteData> get_autocomplete_suggestions(int line_number, int column, std::map<std::string, std::string>& buffer_map); std::vector<AutoCompleteData> get_autocomplete_suggestions(int line_number, int column, std::map<std::string, std::string>& buffer_map);
Glib::Dispatcher autocomplete_done; Glib::Dispatcher autocomplete_done;
sigc::connection autocomplete_done_connection;
Glib::Dispatcher autocomplete_fail; Glib::Dispatcher autocomplete_fail;
sigc::connection autocomplete_fail_connection;
bool autocomplete_starting=false; bool autocomplete_starting=false;
std::atomic<bool> autocomplete_cancel_starting; std::atomic<bool> autocomplete_cancel_starting;
guint last_keyval=0; guint last_keyval=0;
@ -108,13 +113,13 @@ namespace Source {
class ClangViewRefactor : public ClangViewAutocomplete { class ClangViewRefactor : public ClangViewAutocomplete {
public: public:
ClangViewRefactor(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path, Glib::RefPtr<Gsv::Language> language); ClangViewRefactor(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path, Glib::RefPtr<Gsv::Language> language);
~ClangViewRefactor(); protected:
sigc::connection delayed_tag_similar_tokens_connection;
private: private:
std::list<std::pair<Glib::RefPtr<Gtk::TextMark>, Glib::RefPtr<Gtk::TextMark> > > similar_token_marks; std::list<std::pair<Glib::RefPtr<Gtk::TextMark>, Glib::RefPtr<Gtk::TextMark> > > similar_token_marks;
void tag_similar_tokens(const Token &token); void tag_similar_tokens(const Token &token);
Glib::RefPtr<Gtk::TextTag> similar_tokens_tag; Glib::RefPtr<Gtk::TextTag> similar_tokens_tag;
Token last_tagged_token; Token last_tagged_token;
sigc::connection delayed_tag_similar_tokens_connection;
std::unique_ptr<SelectionDialog> selection_dialog; std::unique_ptr<SelectionDialog> selection_dialog;
bool renaming=false; bool renaming=false;
}; };
@ -122,6 +127,7 @@ namespace Source {
class ClangView : public ClangViewRefactor { class ClangView : public ClangViewRefactor {
public: public:
ClangView(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path, Glib::RefPtr<Gsv::Language> language); ClangView(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path, Glib::RefPtr<Gsv::Language> language);
virtual void async_delete();
}; };
} }

108
src/terminal.cc

@ -8,6 +8,8 @@
#include <iostream> //TODO: remove #include <iostream> //TODO: remove
using namespace std; //TODO: remove using namespace std; //TODO: remove
const ssize_t buffer_size=131072;
//A working implementation of popen3, with all pipes getting closed properly. //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 //TODO: Eidheim is going to publish this one on his github, along with example uses
pid_t popen3(const std::string &command, const std::string &path, 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) {
@ -144,8 +146,59 @@ Terminal::Terminal() {
}); });
} }
int Terminal::execute(const std::string &command, const boost::filesystem::path &path) { int Terminal::execute(const std::string &command, const boost::filesystem::path &path, bool use_pipes) {
JDEBUG("start"); int stdin_fd, stdout_fd, stderr_fd;
pid_t pid;
if(use_pipes)
pid=popen3(command, path.string(), &stdin_fd, &stdout_fd, &stderr_fd);
else
pid=popen3(command, path.string(), nullptr, nullptr, nullptr);
if (pid<=0) {
async_print("Error: Failed to run command: " + command + "\n");
return -1;
}
else {
if(use_pipes) {
std::thread stderr_thread([this, stderr_fd](){
char buffer[buffer_size];
ssize_t n;
while ((n=read(stderr_fd, buffer, buffer_size)) > 0) {
std::string message;
message.reserve(n);
for(ssize_t c=0;c<n;c++)
message+=buffer[c];
async_print(message, true);
}
});
stderr_thread.detach();
std::thread stdout_thread([this, stdout_fd](){
char buffer[buffer_size];
ssize_t n;
while ((n=read(stdout_fd, buffer, buffer_size)) > 0) {
std::string message;
message.reserve(n);
for(ssize_t c=0;c<n;c++)
message+=buffer[c];
async_print(message);
}
});
stdout_thread.detach();
}
int exit_code;
waitpid(pid, &exit_code, 0);
if(use_pipes) {
close(stdin_fd);
close(stdout_fd);
close(stderr_fd);
}
return exit_code;
}
}
int Terminal::execute(std::istream &stdin_stream, std::ostream &stdout_stream, const std::string &command, const boost::filesystem::path &path) {
int stdin_fd, stdout_fd, stderr_fd; int stdin_fd, stdout_fd, stderr_fd;
auto pid=popen3(command, path.string(), &stdin_fd, &stdout_fd, &stderr_fd); auto pid=popen3(command, path.string(), &stdin_fd, &stdout_fd, &stderr_fd);
@ -155,42 +208,59 @@ int Terminal::execute(const std::string &command, const boost::filesystem::path
} }
else { else {
std::thread stderr_thread([this, stderr_fd](){ std::thread stderr_thread([this, stderr_fd](){
char buffer[1024]; char buffer[buffer_size];
ssize_t n; ssize_t n;
while ((n=read(stderr_fd, buffer, 1024)) > 0) { while ((n=read(stderr_fd, buffer, buffer_size)) > 0) {
std::string message; std::string message;
message.reserve(n);
for(ssize_t c=0;c<n;c++) for(ssize_t c=0;c<n;c++)
message+=buffer[c]; message+=buffer[c];
async_print(message, true); async_print(message, true);
} }
}); });
stderr_thread.detach(); stderr_thread.detach();
std::thread stdout_thread([this, stdout_fd](){ std::thread stdout_thread([this, &stdout_stream, stdout_fd](){
char buffer[1024]; char buffer[buffer_size];
ssize_t n; ssize_t n;
while ((n=read(stdout_fd, buffer, 1024)) > 0) { while ((n=read(stdout_fd, buffer, buffer_size)) > 0) {
std::string message; Glib::ustring umessage;
umessage.reserve(n);
for(ssize_t c=0;c<n;c++) for(ssize_t c=0;c<n;c++)
message+=buffer[c]; umessage+=buffer[c];
async_print(message); Glib::ustring::iterator iter;
while(!umessage.validate(iter)) {
auto next_char_iter=iter;
next_char_iter++;
umessage.replace(iter, next_char_iter, "?");
}
stdout_stream.write(umessage.data(), n);
} }
}); });
stdout_thread.detach(); stdout_thread.detach();
char buffer[buffer_size];
for(;;) {
stdin_stream.readsome(buffer, buffer_size);
auto read_n=stdin_stream.gcount();
if(read_n==0)
break;
auto write_n=write(stdin_fd, buffer, read_n);
if(write_n==0)
break;
}
close(stdin_fd);
int exit_code; int exit_code;
waitpid(pid, &exit_code, 0); waitpid(pid, &exit_code, 0);
close(stdin_fd);
close(stdout_fd); close(stdout_fd);
close(stderr_fd); close(stderr_fd);
JDEBUG("end");
return exit_code; return exit_code;
} }
} }
void Terminal::async_execute(const std::string &command, const boost::filesystem::path &path, std::function<void(int exit_code)> callback) { void Terminal::async_execute(const std::string &command, const boost::filesystem::path &path, std::function<void(int exit_code)> callback) {
std::thread async_execute_thread([this, command, path, callback](){ std::thread async_execute_thread([this, command, path, callback](){
JDEBUG("start");
int stdin_fd, stdout_fd, stderr_fd; int stdin_fd, stdout_fd, stderr_fd;
async_executes_mutex.lock(); async_executes_mutex.lock();
stdin_buffer.clear(); stdin_buffer.clear();
@ -205,10 +275,11 @@ void Terminal::async_execute(const std::string &command, const boost::filesystem
} }
else { else {
std::thread stderr_thread([this, stderr_fd](){ std::thread stderr_thread([this, stderr_fd](){
char buffer[1024]; char buffer[buffer_size];
ssize_t n; ssize_t n;
while ((n=read(stderr_fd, buffer, 1024)) > 0) { while ((n=read(stderr_fd, buffer, buffer_size)) > 0) {
std::string message; std::string message;
message.reserve(n);
for(ssize_t c=0;c<n;c++) for(ssize_t c=0;c<n;c++)
message+=buffer[c]; message+=buffer[c];
async_print(message, true); async_print(message, true);
@ -216,10 +287,11 @@ void Terminal::async_execute(const std::string &command, const boost::filesystem
}); });
stderr_thread.detach(); stderr_thread.detach();
std::thread stdout_thread([this, stdout_fd](){ std::thread stdout_thread([this, stdout_fd](){
char buffer[1024]; char buffer[buffer_size];
ssize_t n; ssize_t n;
while ((n=read(stdout_fd, buffer, 1024)) > 0) { while ((n=read(stdout_fd, buffer, buffer_size)) > 0) {
std::string message; std::string message;
message.reserve(n);
for(ssize_t c=0;c<n;c++) for(ssize_t c=0;c<n;c++)
message+=buffer[c]; message+=buffer[c];
async_print(message); async_print(message);
@ -244,8 +316,6 @@ void Terminal::async_execute(const std::string &command, const boost::filesystem
if(callback) if(callback)
callback(exit_code); callback(exit_code);
JDEBUG("end");
} }
}); });
async_execute_thread.detach(); async_execute_thread.detach();

4
src/terminal.h

@ -8,6 +8,7 @@
#include <thread> #include <thread>
#include <atomic> #include <atomic>
#include <list> #include <list>
#include <iostream>
class Terminal : public Gtk::TextView { class Terminal : public Gtk::TextView {
public: public:
@ -33,7 +34,8 @@ public:
}; };
Terminal(); Terminal();
int execute(const std::string &command, const boost::filesystem::path &path=""); int execute(const std::string &command, const boost::filesystem::path &path="", bool use_pipes=true);
int execute(std::istream &stdin_stream, std::ostream &stdout_stream, const std::string &command, const boost::filesystem::path &path="");
void async_execute(const std::string &command, const boost::filesystem::path &path="", std::function<void(int exit_code)> callback=nullptr); void async_execute(const std::string &command, const boost::filesystem::path &path="", std::function<void(int exit_code)> callback=nullptr);
void kill_last_async_execute(bool force=false); void kill_last_async_execute(bool force=false);
void kill_async_executes(bool force=false); void kill_async_executes(bool force=false);

227
src/terminal_win.cc

@ -8,8 +8,11 @@
#include <iostream> //TODO: remove #include <iostream> //TODO: remove
using namespace std; //TODO: remove using namespace std; //TODO: remove
#define BUFSIZE 1024 const size_t buffer_size=131072;
//Based on the example at https://msdn.microsoft.com/en-us/library/windows/desktop/ms682499(v=vs.85).aspx
//Note: on Windows it seems impossible to specify which pipes to use
//Thus, if stdin_h, stdout_h and stderr all are NULL, the out,err,in is sent to the parent process instead
HANDLE popen3(const std::string &command, const std::string &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_Rd = NULL;
HANDLE g_hChildStd_IN_Wr = NULL; HANDLE g_hChildStd_IN_Wr = NULL;
@ -21,43 +24,49 @@ HANDLE popen3(const std::string &command, const std::string &path, HANDLE *stdin
SECURITY_ATTRIBUTES saAttr; SECURITY_ATTRIBUTES saAttr;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE; saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL; saAttr.lpSecurityDescriptor = NULL;
if (!CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0)) if(stdin_h!=nullptr) {
return NULL; if (!CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0))
if(!SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0)) { return NULL;
CloseHandle(g_hChildStd_IN_Rd); if(!SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0)) {
CloseHandle(g_hChildStd_IN_Wr); CloseHandle(g_hChildStd_IN_Rd);
return NULL; 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)) { if(stdout_h!=nullptr) {
CloseHandle(g_hChildStd_IN_Rd); if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0)) {
CloseHandle(g_hChildStd_IN_Wr); if(stdin_h!=nullptr) CloseHandle(g_hChildStd_IN_Rd);
CloseHandle(g_hChildStd_OUT_Rd); if(stdin_h!=nullptr) CloseHandle(g_hChildStd_IN_Wr);
CloseHandle(g_hChildStd_OUT_Wr); return NULL;
return NULL; }
if(!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0)) {
if(stdin_h!=nullptr) CloseHandle(g_hChildStd_IN_Rd);
if(stdin_h!=nullptr) 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)) { if(stderr_h!=nullptr) {
CloseHandle(g_hChildStd_IN_Rd); if (!CreatePipe(&g_hChildStd_ERR_Rd, &g_hChildStd_ERR_Wr, &saAttr, 0)) {
CloseHandle(g_hChildStd_IN_Wr); if(stdin_h!=nullptr) CloseHandle(g_hChildStd_IN_Rd);
CloseHandle(g_hChildStd_OUT_Rd); if(stdin_h!=nullptr) CloseHandle(g_hChildStd_IN_Wr);
CloseHandle(g_hChildStd_OUT_Wr); if(stdout_h!=nullptr) CloseHandle(g_hChildStd_OUT_Rd);
CloseHandle(g_hChildStd_ERR_Rd); if(stdout_h!=nullptr) CloseHandle(g_hChildStd_OUT_Wr);
CloseHandle(g_hChildStd_ERR_Wr); return NULL;
return NULL; }
if(!SetHandleInformation(g_hChildStd_ERR_Rd, HANDLE_FLAG_INHERIT, 0)) {
if(stdin_h!=nullptr) CloseHandle(g_hChildStd_IN_Rd);
if(stdin_h!=nullptr) CloseHandle(g_hChildStd_IN_Wr);
if(stdout_h!=nullptr) CloseHandle(g_hChildStd_OUT_Rd);
if(stdout_h!=nullptr) CloseHandle(g_hChildStd_OUT_Wr);
CloseHandle(g_hChildStd_ERR_Rd);
CloseHandle(g_hChildStd_ERR_Wr);
return NULL;
}
} }
PROCESS_INFORMATION process_info; PROCESS_INFORMATION process_info;
@ -66,11 +75,12 @@ HANDLE popen3(const std::string &command, const std::string &path, HANDLE *stdin
ZeroMemory(&process_info, sizeof(PROCESS_INFORMATION)); ZeroMemory(&process_info, sizeof(PROCESS_INFORMATION));
ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
siStartInfo.cb = sizeof(STARTUPINFO); siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = g_hChildStd_ERR_Wr; if(stdin_h!=nullptr) siStartInfo.hStdInput = g_hChildStd_IN_Rd;
siStartInfo.hStdOutput = g_hChildStd_OUT_Wr; if(stdout_h!=nullptr) siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
siStartInfo.hStdInput = g_hChildStd_IN_Rd; if(stderr_h!=nullptr) siStartInfo.hStdError = g_hChildStd_ERR_Wr;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES; if(stdin_h!=nullptr || stdout_h!=nullptr || stderr_h!=nullptr)
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
char* path_ptr; char* path_ptr;
if(path=="") if(path=="")
@ -95,9 +105,9 @@ HANDLE popen3(const std::string &command, const std::string &path, HANDLE *stdin
if(!bSuccess) { if(!bSuccess) {
CloseHandle(process_info.hProcess); CloseHandle(process_info.hProcess);
CloseHandle(process_info.hThread); CloseHandle(process_info.hThread);
CloseHandle(g_hChildStd_IN_Rd); if(stdin_h!=nullptr) CloseHandle(g_hChildStd_IN_Rd);
CloseHandle(g_hChildStd_OUT_Wr); if(stdout_h!=nullptr) CloseHandle(g_hChildStd_OUT_Wr);
CloseHandle(g_hChildStd_ERR_Wr); if(stderr_h!=nullptr) CloseHandle(g_hChildStd_ERR_Wr);
return NULL; return NULL;
} }
else { else {
@ -106,14 +116,14 @@ HANDLE popen3(const std::string &command, const std::string &path, HANDLE *stdin
// of the child process, for example. // of the child process, for example.
CloseHandle(process_info.hThread); CloseHandle(process_info.hThread);
CloseHandle(g_hChildStd_IN_Rd); if(stdin_h!=nullptr) CloseHandle(g_hChildStd_IN_Rd);
CloseHandle(g_hChildStd_OUT_Wr); if(stdout_h!=nullptr) CloseHandle(g_hChildStd_OUT_Wr);
CloseHandle(g_hChildStd_ERR_Wr); if(stderr_h!=nullptr) CloseHandle(g_hChildStd_ERR_Wr);
} }
*stdin_h=g_hChildStd_IN_Wr; if(stdin_h!=NULL) *stdin_h=g_hChildStd_IN_Wr;
*stdout_h=g_hChildStd_OUT_Rd; if(stdout_h!=NULL) *stdout_h=g_hChildStd_OUT_Rd;
*stderr_h=g_hChildStd_ERR_Rd; if(stderr_h!=NULL) *stderr_h=g_hChildStd_ERR_Rd;
return process_info.hProcess; return process_info.hProcess;
} }
@ -181,8 +191,68 @@ 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, bool use_pipes) {
int Terminal::execute(const std::string &command, const boost::filesystem::path &path) { HANDLE stdin_h, stdout_h, stderr_h;
HANDLE process;
if(use_pipes)
process=popen3(command, path.string(), &stdin_h, &stdout_h, &stderr_h);
else
process=popen3(command, path.string(), nullptr, nullptr, nullptr);
if(process==NULL) {
async_print("Error: Failed to run command: " + command + "\n");
return -1;
}
if(use_pipes) {
std::thread stderr_thread([this, stderr_h](){
DWORD n;
CHAR buffer[buffer_size];
for (;;) {
BOOL bSuccess = ReadFile(stderr_h, buffer, static_cast<DWORD>(buffer_size), &n, NULL);
if(!bSuccess || n == 0)
break;
std::string message;
message.reserve(n);
for(DWORD c=0;c<n;c++)
message+=buffer[c];
async_print(message, true);
}
});
stderr_thread.detach();
std::thread stdout_thread([this, stdout_h](){
DWORD n;
CHAR buffer[buffer_size];
for (;;) {
BOOL bSuccess = ReadFile(stdout_h, buffer, static_cast<DWORD>(buffer_size), &n, NULL);
if(!bSuccess || n == 0)
break;
std::string message;
message.reserve(n);
for(DWORD c=0;c<n;c++)
message+=buffer[c];
async_print(message);
}
});
stdout_thread.detach();
}
unsigned long exit_code;
WaitForSingleObject(process, INFINITE);
GetExitCodeProcess(process, &exit_code);
CloseHandle(process);
if(use_pipes) {
CloseHandle(stdin_h);
CloseHandle(stdout_h);
CloseHandle(stderr_h);
}
return exit_code;
}
int Terminal::execute(std::istream &stdin_stream, std::ostream &stdout_stream, const std::string &command, const boost::filesystem::path &path) {
HANDLE stdin_h, stdout_h, stderr_h; HANDLE stdin_h, stdout_h, stderr_h;
auto process=popen3(command, path.string(), &stdin_h, &stdout_h, &stderr_h); auto process=popen3(command, path.string(), &stdin_h, &stdout_h, &stderr_h);
@ -192,13 +262,14 @@ int Terminal::execute(const std::string &command, const boost::filesystem::path
} }
std::thread stderr_thread([this, stderr_h](){ std::thread stderr_thread([this, stderr_h](){
DWORD n; DWORD n;
CHAR buffer[BUFSIZE]; CHAR buffer[buffer_size];
for (;;) { for (;;) {
BOOL bSuccess = ReadFile(stderr_h, buffer, BUFSIZE, &n, NULL); BOOL bSuccess = ReadFile(stderr_h, buffer, static_cast<DWORD>(buffer_size), &n, NULL);
if(!bSuccess || n == 0) if(!bSuccess || n == 0)
break; break;
std::string message; std::string message;
message.reserve(n);
for(DWORD c=0;c<n;c++) for(DWORD c=0;c<n;c++)
message+=buffer[c]; message+=buffer[c];
async_print(message, true); async_print(message, true);
@ -206,28 +277,46 @@ int Terminal::execute(const std::string &command, const boost::filesystem::path
}); });
stderr_thread.detach(); stderr_thread.detach();
std::thread stdout_thread([this, stdout_h](){ std::thread stdout_thread([this, &stdout_stream, stdout_h](){
DWORD n; DWORD n;
CHAR buffer[BUFSIZE]; CHAR buffer[buffer_size];
for (;;) { for (;;) {
BOOL bSuccess = ReadFile(stdout_h, buffer, BUFSIZE, &n, NULL); BOOL bSuccess = ReadFile(stdout_h, buffer, static_cast<DWORD>(buffer_size), &n, NULL);
if(!bSuccess || n == 0) if(!bSuccess || n == 0)
break; break;
Glib::ustring umessage;
std::string message; umessage.reserve(n);
for(DWORD c=0;c<n;c++) for(DWORD c=0;c<n;c++)
message+=buffer[c]; umessage+=buffer[c];
async_print(message); Glib::ustring::iterator iter;
while(!umessage.validate(iter)) {
auto next_char_iter=iter;
next_char_iter++;
umessage.replace(iter, next_char_iter, "?");
}
stdout_stream.write(umessage.data(), static_cast<ssize_t>(n));
} }
}); });
stdout_thread.detach(); stdout_thread.detach();
CHAR buffer[buffer_size];
for(;;) {
stdin_stream.readsome(buffer, buffer_size);
auto read_n=stdin_stream.gcount();
if(read_n==0)
break;
DWORD write_n;
BOOL bSuccess = WriteFile(stdin_h, buffer, static_cast<DWORD>(read_n), &write_n, NULL);
if(!bSuccess || write_n==0)
break;
}
CloseHandle(stdin_h);
unsigned long exit_code; unsigned long exit_code;
WaitForSingleObject(process, INFINITE); WaitForSingleObject(process, INFINITE);
GetExitCodeProcess(process, &exit_code); GetExitCodeProcess(process, &exit_code);
CloseHandle(process); CloseHandle(process);
CloseHandle(stdin_h);
CloseHandle(stdout_h); CloseHandle(stdout_h);
CloseHandle(stderr_h); CloseHandle(stderr_h);
return exit_code; return exit_code;
@ -252,13 +341,14 @@ void Terminal::async_execute(const std::string &command, const boost::filesystem
std::thread stderr_thread([this, stderr_h](){ std::thread stderr_thread([this, stderr_h](){
DWORD n; DWORD n;
CHAR buffer[BUFSIZE]; CHAR buffer[buffer_size];
for (;;) { for (;;) {
BOOL bSuccess = ReadFile(stderr_h, buffer, BUFSIZE, &n, NULL); BOOL bSuccess = ReadFile(stderr_h, buffer, static_cast<DWORD>(buffer_size), &n, NULL);
if(!bSuccess || n == 0) if(!bSuccess || n == 0)
break; break;
std::string message; std::string message;
message.reserve(n);
for(DWORD c=0;c<n;c++) for(DWORD c=0;c<n;c++)
message+=buffer[c]; message+=buffer[c];
async_print(message, true); async_print(message, true);
@ -268,13 +358,14 @@ void Terminal::async_execute(const std::string &command, const boost::filesystem
std::thread stdout_thread([this, stdout_h](){ std::thread stdout_thread([this, stdout_h](){
DWORD n; DWORD n;
CHAR buffer[BUFSIZE]; CHAR buffer[buffer_size];
for (;;) { for (;;) {
BOOL bSuccess = ReadFile(stdout_h, buffer, BUFSIZE, &n, NULL); BOOL bSuccess = ReadFile(stdout_h, buffer, static_cast<DWORD>(buffer_size), &n, NULL);
if(!bSuccess || n == 0) if(!bSuccess || n == 0)
break; break;
std::string message; std::string message;
message.reserve(n);
for(DWORD c=0;c<n;c++) for(DWORD c=0;c<n;c++)
message+=buffer[c]; message+=buffer[c];
async_print(message); async_print(message);

387
src/window.cc

@ -22,31 +22,18 @@ namespace sigc {
#endif #endif
} }
void Window::generate_keybindings() { Window::Window() : compiling(false) {
for (auto &i : Singleton::Config::window()->keybindings) {
auto key = i.second.get_value<std::string>();
menu.key_map[i.first] = key;
}
}
Window::Window() : box(Gtk::ORIENTATION_VERTICAL), compiling(false) {
JDEBUG("start"); JDEBUG("start");
set_title("juCi++"); set_title("juCi++");
set_events(Gdk::POINTER_MOTION_MASK|Gdk::FOCUS_CHANGE_MASK|Gdk::SCROLL_MASK); set_events(Gdk::POINTER_MOTION_MASK|Gdk::FOCUS_CHANGE_MASK|Gdk::SCROLL_MASK);
set_menu_actions();
configure(); configure();
set_default_size(Singleton::Config::window()->default_size.first, Singleton::Config::window()->default_size.second); set_default_size(Singleton::Config::window()->default_size.first, Singleton::Config::window()->default_size.second);
//PluginApi(&this->notebook, &this->menu); //PluginApi(&this->notebook, &this->menu);
add(box); add(vpaned);
//TODO: Do not use deprecated ui_manager? And make menu shortcuts update when config.json is saved (in configure())
generate_keybindings();
create_menu();
menu.build();
add_accel_group(menu.ui_manager->get_accel_group());
box.pack_start(menu.get_widget(), Gtk::PACK_SHRINK);
directory_and_notebook_panes.pack1(*Singleton::directories(), Gtk::SHRINK); directory_and_notebook_panes.pack1(*Singleton::directories(), Gtk::SHRINK);
notebook_vbox.pack_start(notebook); notebook_vbox.pack_start(notebook);
notebook_vbox.pack_end(entry_box, Gtk::PACK_SHRINK); notebook_vbox.pack_end(entry_box, Gtk::PACK_SHRINK);
@ -63,7 +50,6 @@ Window::Window() : box(Gtk::ORIENTATION_VERTICAL), compiling(false) {
terminal_vbox.pack_end(info_and_status_hbox, Gtk::PACK_SHRINK); terminal_vbox.pack_end(info_and_status_hbox, Gtk::PACK_SHRINK);
vpaned.pack2(terminal_vbox, true, true); vpaned.pack2(terminal_vbox, true, true);
box.pack_end(vpaned);
show_all_children(); show_all_children();
Singleton::directories()->on_row_activated=[this](const std::string &file) { Singleton::directories()->on_row_activated=[this](const std::string &file) {
@ -78,13 +64,11 @@ Window::Window() : box(Gtk::ORIENTATION_VERTICAL), compiling(false) {
}); });
entry_box.signal_show().connect([this](){ entry_box.signal_show().connect([this](){
box.set_focus_chain({&vpaned});
vpaned.set_focus_chain({&directory_and_notebook_panes}); vpaned.set_focus_chain({&directory_and_notebook_panes});
directory_and_notebook_panes.set_focus_chain({&notebook_vbox}); directory_and_notebook_panes.set_focus_chain({&notebook_vbox});
notebook_vbox.set_focus_chain({&entry_box}); notebook_vbox.set_focus_chain({&entry_box});
}); });
entry_box.signal_hide().connect([this](){ entry_box.signal_hide().connect([this](){
box.unset_focus_chain();
vpaned.unset_focus_chain(); vpaned.unset_focus_chain();
directory_and_notebook_panes.unset_focus_chain(); directory_and_notebook_panes.unset_focus_chain();
notebook_vbox.unset_focus_chain(); notebook_vbox.unset_focus_chain();
@ -104,24 +88,8 @@ Window::Window() : box(Gtk::ORIENTATION_VERTICAL), compiling(false) {
notebook.get_current_view()->search_highlight(last_search, case_sensitive_search, regex_search); notebook.get_current_view()->search_highlight(last_search, case_sensitive_search, regex_search);
} }
if(auto menu_item=dynamic_cast<Gtk::MenuItem*>(menu.ui_manager->get_widget("/MenuBar/SourceMenu/SourceGotoDeclaration"))) activate_menu_items();
menu_item->set_sensitive((bool)notebook.get_current_view()->get_declaration_location);
if(auto menu_item=dynamic_cast<Gtk::MenuItem*>(menu.ui_manager->get_widget("/MenuBar/SourceMenu/SourceGotoMethod")))
menu_item->set_sensitive((bool)notebook.get_current_view()->goto_method);
if(auto menu_item=dynamic_cast<Gtk::MenuItem*>(menu.ui_manager->get_widget("/MenuBar/SourceMenu/SourceRename")))
menu_item->set_sensitive((bool)notebook.get_current_view()->rename_similar_tokens);
if(auto menu_item=dynamic_cast<Gtk::MenuItem*>(menu.ui_manager->get_widget("/MenuBar/SourceMenu/SourceGotoNextDiagnostic")))
menu_item->set_sensitive((bool)notebook.get_current_view()->goto_next_diagnostic);
if(auto menu_item=dynamic_cast<Gtk::MenuItem*>(menu.ui_manager->get_widget("/MenuBar/SourceMenu/SourceApplyFixIts")))
menu_item->set_sensitive((bool)notebook.get_current_view()->apply_fix_its);
if(auto menu_item=dynamic_cast<Gtk::MenuItem*>(menu.ui_manager->get_widget("/MenuBar/SourceMenu/SourceFindDocumentation")))
menu_item->set_sensitive((bool)notebook.get_current_view()->get_token_data);
Singleton::directories()->select(notebook.get_current_view()->file_path); Singleton::directories()->select(notebook.get_current_view()->file_path);
if(auto source_view=dynamic_cast<Source::ClangView*>(notebook.get_current_view())) { if(auto source_view=dynamic_cast<Source::ClangView*>(notebook.get_current_view())) {
@ -158,54 +126,65 @@ Window::Window() : box(Gtk::ORIENTATION_VERTICAL), compiling(false) {
} // Window constructor } // Window constructor
void Window::configure() { void Window::configure() {
Singleton::Config::main()->read();
auto style_context = Gtk::StyleContext::create(); auto style_context = Gtk::StyleContext::create();
auto screen = Gdk::Screen::get_default(); auto screen = Gdk::Screen::get_default();
auto css_provider = Gtk::CssProvider::get_named(Singleton::Config::window()->theme_name, Singleton::Config::window()->theme_variant); auto css_provider = Gtk::CssProvider::get_named(Singleton::Config::window()->theme_name, Singleton::Config::window()->theme_variant);
//TODO: add check if theme exists, or else write error to Singleton::terminal() //TODO: add check if theme exists, or else write error to Singleton::terminal()
style_context->add_provider_for_screen(screen, css_provider, GTK_STYLE_PROVIDER_PRIORITY_SETTINGS); style_context->add_provider_for_screen(screen, css_provider, GTK_STYLE_PROVIDER_PRIORITY_SETTINGS);
Singleton::menu()->set_keys();
} }
void Window::create_menu() { void Window::set_menu_actions() {
menu.action_group->add(Gtk::Action::create("FileQuit", "Quit juCi++"), Gtk::AccelKey(menu.key_map["quit"]), [this]() { auto menu = Singleton::menu();
menu->add_action("about", [this]() {
about.show();
about.present();
});
menu->add_action("preferences", [this]() {
notebook.open(Singleton::Config::main()->juci_home_path()/"config"/"config.json");
});
menu->add_action("quit", [this]() {
hide(); hide();
}); });
menu.action_group->add(Gtk::Action::create("FileNewFile", "New File"), Gtk::AccelKey(menu.key_map["new_file"]), [this]() {
boost::filesystem::path path = Dialog::new_file(); menu->add_action("new_file", [this]() {
if(path!="") { boost::filesystem::path path = Dialog::new_file();
if(boost::filesystem::exists(path)) { if(path!="") {
Singleton::terminal()->print("Error: "+path.string()+" already exists.\n"); if(boost::filesystem::exists(path)) {
} Singleton::terminal()->print("Error: "+path.string()+" already exists.\n");
else {
if(filesystem::write(path)) {
if(Singleton::directories()->current_path!="")
Singleton::directories()->update();
notebook.open(path.string());
Singleton::terminal()->print("New file "+path.string()+" created.\n");
}
else
Singleton::terminal()->print("Error: could not create new file "+path.string()+".\n");
}
} }
}); else {
menu.action_group->add(Gtk::Action::create("FileNewFolder", "New Folder"), Gtk::AccelKey(menu.key_map["new_folder"]), [this]() { if(filesystem::write(path)) {
auto time_now=std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
boost::filesystem::path path = Dialog::new_folder();
if(path!="" && boost::filesystem::exists(path)) {
if(boost::filesystem::last_write_time(path)>=time_now) {
if(Singleton::directories()->current_path!="") if(Singleton::directories()->current_path!="")
Singleton::directories()->update(); Singleton::directories()->update();
Singleton::terminal()->print("New folder "+path.string()+" created.\n"); notebook.open(path.string());
Singleton::terminal()->print("New file "+path.string()+" created.\n");
} }
else else
Singleton::terminal()->print("Error: "+path.string()+" already exists.\n"); Singleton::terminal()->print("Error: could not create new file "+path.string()+".\n");
}
}
});
menu->add_action("new_folder", [this]() {
auto time_now=std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
boost::filesystem::path path = Dialog::new_folder();
if(path!="" && boost::filesystem::exists(path)) {
if(boost::filesystem::last_write_time(path)>=time_now) {
if(Singleton::directories()->current_path!="")
Singleton::directories()->update();
Singleton::terminal()->print("New folder "+path.string()+" created.\n");
} }
else
Singleton::terminal()->print("Error: "+path.string()+" already exists.\n");
Singleton::directories()->select(path); Singleton::directories()->select(path);
}
}); });
menu.action_group->add(Gtk::Action::create("FileNewProject", "New Project")); menu->add_action("new_project_cpp", [this]() {
menu.action_group->add(Gtk::Action::create("FileNewProjectCpp", "C++"), [this]() { boost::filesystem::path project_path = Dialog::new_folder();
boost::filesystem::path project_path = Dialog::new_folder(); if(project_path!="") {
if(project_path=="")
return;
auto project_name=project_path.filename().string(); auto project_name=project_path.filename().string();
for(size_t c=0;c<project_name.size();c++) { for(size_t c=0;c<project_name.size();c++) {
if(project_name[c]==' ') if(project_name[c]==' ')
@ -232,74 +211,55 @@ void Window::create_menu() {
} }
else else
Singleton::terminal()->print("Error: Could not create project "+project_path.string()+"\n"); Singleton::terminal()->print("Error: Could not create project "+project_path.string()+"\n");
}
}); });
menu.action_group->add(Gtk::Action::create("FileOpenFile", "Open File"), Gtk::AccelKey(menu.key_map["open_file"]), [this]() {
notebook.open(Dialog::select_file()); menu->add_action("open_file", [this]() {
auto path=Dialog::select_file();
if(path!="")
notebook.open(path);
}); });
menu.action_group->add(Gtk::Action::create("FileOpenFolder", "Open Folder"), Gtk::AccelKey(menu.key_map["open_folder"]), [this]() { menu->add_action("open_folder", [this]() {
auto path = Dialog::select_folder(); auto path = Dialog::select_folder();
if (path!="" && boost::filesystem::exists(path)) if (path!="" && boost::filesystem::exists(path))
Singleton::directories()->open(path); Singleton::directories()->open(path);
}); });
menu.action_group->add(Gtk::Action::create("FileSaveAs", "Save As"), Gtk::AccelKey(menu.key_map["save_as"]), [this]() {
auto path = Dialog::save_file(); menu->add_action("save", [this]() {
if(path!="") { if(notebook.get_current_page()!=-1) {
std::ofstream file(path); if(notebook.save_current()) {
if(file) { if(notebook.get_current_page()!=-1) {
file << notebook.get_current_view()->get_buffer()->get_text(); if(notebook.get_current_view()->file_path==Singleton::Config::main()->juci_home_path()/"config"/"config.json") {
file.close(); configure();
if(Singleton::directories()->current_path!="") for(int c=0;c<notebook.size();c++) {
Singleton::directories()->update(); notebook.get_view(c)->configure();
notebook.open(path); notebook.configure(c);
Singleton::terminal()->print("File saved to: " + notebook.get_current_view()->file_path.string()+"\n"); }
}
}
} }
else
Singleton::terminal()->print("Error saving file\n");
} }
});
menu.action_group->add(Gtk::Action::create("Preferences", "Preferences..."), Gtk::AccelKey(menu.key_map["preferences"]), [this]() {
notebook.open(Singleton::Config::main()->juci_home_path()/"config"/"config.json");
}); });
menu->add_action("save_as", [this]() {
menu.action_group->add(Gtk::Action::create("FileSave", "Save"), Gtk::AccelKey(menu.key_map["save"]), [this]() { if(notebook.get_current_page()!=-1) {
if(notebook.save_current()) { auto path = Dialog::save_file();
if(notebook.get_current_page()!=-1) { if(path!="") {
if(notebook.get_current_view()->file_path==Singleton::Config::main()->juci_home_path()/"config"/"config.json") { std::ofstream file(path);
configure(); if(file) {
for(int c=0;c<notebook.size();c++) { file << notebook.get_current_view()->get_buffer()->get_text();
notebook.get_view(c)->configure(); file.close();
notebook.configure(c); if(Singleton::directories()->current_path!="")
} Singleton::directories()->update();
notebook.open(path);
Singleton::terminal()->print("File saved to: " + notebook.get_current_view()->file_path.string()+"\n");
} }
else
Singleton::terminal()->print("Error saving file\n");
} }
} }
}); });
menu.action_group->add(Gtk::Action::create("EditCopy", "Copy"), Gtk::AccelKey(menu.key_map["edit_copy"]), [this]() { menu->add_action("edit_undo", [this]() {
auto widget=get_focus();
if(auto entry=dynamic_cast<Gtk::Entry*>(widget))
entry->copy_clipboard();
else if(auto text_view=dynamic_cast<Gtk::TextView*>(widget))
text_view->get_buffer()->copy_clipboard(Gtk::Clipboard::get());
});
menu.action_group->add(Gtk::Action::create("EditCut", "Cut"), Gtk::AccelKey(menu.key_map["edit_cut"]), [this]() {
auto widget=get_focus();
if(auto entry=dynamic_cast<Gtk::Entry*>(widget))
entry->cut_clipboard();
else if(notebook.get_current_page()!=-1)
notebook.get_current_view()->get_buffer()->cut_clipboard(Gtk::Clipboard::get());
});
menu.action_group->add(Gtk::Action::create("EditPaste", "Paste"), Gtk::AccelKey(menu.key_map["edit_paste"]), [this]() {
auto widget=get_focus();
if(auto entry=dynamic_cast<Gtk::Entry*>(widget))
entry->paste_clipboard();
else if(notebook.get_current_page()!=-1)
notebook.get_current_view()->paste();
});
menu.action_group->add(Gtk::Action::create("EditFind", "Find"), Gtk::AccelKey(menu.key_map["edit_find"]), [this]() {
search_and_replace_entry();
});
menu.action_group->add(Gtk::Action::create("EditUndo", "Undo"), Gtk::AccelKey(menu.key_map["edit_undo"]), [this]() {
if(notebook.get_current_page()!=-1) { if(notebook.get_current_page()!=-1) {
auto undo_manager = notebook.get_current_view()->get_source_buffer()->get_undo_manager(); auto undo_manager = notebook.get_current_view()->get_source_buffer()->get_undo_manager();
if (undo_manager->can_undo()) { if (undo_manager->can_undo()) {
@ -308,7 +268,7 @@ void Window::create_menu() {
} }
} }
}); });
menu.action_group->add(Gtk::Action::create("EditRedo", "Redo"), Gtk::AccelKey(menu.key_map["edit_redo"]), [this]() { menu->add_action("edit_redo", [this]() {
if(notebook.get_current_page()!=-1) { if(notebook.get_current_page()!=-1) {
auto undo_manager = notebook.get_current_view()->get_source_buffer()->get_undo_manager(); auto undo_manager = notebook.get_current_view()->get_source_buffer()->get_undo_manager();
if(undo_manager->can_redo()) { if(undo_manager->can_redo()) {
@ -317,31 +277,58 @@ void Window::create_menu() {
} }
} }
}); });
menu.action_group->add(Gtk::Action::create("SourceSpellCheck", "Spell Check")); menu->add_action("edit_cut", [this]() {
menu.action_group->add(Gtk::Action::create("SourceSpellCheckBuffer", "Spell Check Buffer"), Gtk::AccelKey(menu.key_map["source_spellcheck"]), [this]() { auto widget=get_focus();
if(auto entry=dynamic_cast<Gtk::Entry*>(widget))
entry->cut_clipboard();
else if(notebook.get_current_page()!=-1)
notebook.get_current_view()->get_buffer()->cut_clipboard(Gtk::Clipboard::get());
});
menu->add_action("edit_copy", [this]() {
auto widget=get_focus();
if(auto entry=dynamic_cast<Gtk::Entry*>(widget))
entry->copy_clipboard();
else if(auto text_view=dynamic_cast<Gtk::TextView*>(widget))
text_view->get_buffer()->copy_clipboard(Gtk::Clipboard::get());
});
menu->add_action("edit_paste", [this]() {
auto widget=get_focus();
if(auto entry=dynamic_cast<Gtk::Entry*>(widget))
entry->paste_clipboard();
else if(notebook.get_current_page()!=-1)
notebook.get_current_view()->paste();
});
menu->add_action("edit_find", [this]() {
search_and_replace_entry();
});
menu->add_action("source_spellcheck", [this]() {
if(notebook.get_current_page()!=-1) if(notebook.get_current_page()!=-1)
notebook.get_current_view()->spellcheck(); notebook.get_current_view()->spellcheck();
}); });
menu.action_group->add(Gtk::Action::create("SourceSpellCheckClear", "Clear Spelling Errors"), Gtk::AccelKey(menu.key_map["source_spellcheck_clear"]), [this]() { menu->add_action("source_spellcheck_clear", [this]() {
if(notebook.get_current_page()!=-1) if(notebook.get_current_page()!=-1)
notebook.get_current_view()->remove_spellcheck_errors(); notebook.get_current_view()->remove_spellcheck_errors();
}); });
menu.action_group->add(Gtk::Action::create("SourceSpellCheckNextError", "Go to next Spelling Error"), Gtk::AccelKey(menu.key_map["source_spellcheck_next_error"]), [this]() { menu->add_action("source_spellcheck_next_error", [this]() {
if(notebook.get_current_page()!=-1) if(notebook.get_current_page()!=-1)
notebook.get_current_view()->goto_next_spellcheck_error(); notebook.get_current_view()->goto_next_spellcheck_error();
}); });
menu.action_group->add(Gtk::Action::create("SourceIndentation", "Indentation"));
menu.action_group->add(Gtk::Action::create("SourceIndentationSetBufferTab", "Set Current Buffer Tab"), Gtk::AccelKey(menu.key_map["source_indentation_set_buffer_tab"]), [this]() { menu->add_action("source_indentation_set_buffer_tab", [this]() {
set_tab_entry(); set_tab_entry();
}); });
menu.action_group->add(Gtk::Action::create("SourceIndentationAutoIndentBuffer", "Auto-Indent Current Buffer"), Gtk::AccelKey(menu.key_map["source_indentation_auto_indent_buffer"]), [this]() { menu->add_action("source_indentation_auto_indent_buffer", [this]() {
Singleton::terminal()->print("Auto-Indent Current Buffer will soon be implemented.\n"); if(notebook.get_current_page()!=-1 && notebook.get_current_view()->auto_indent)
notebook.get_current_view()->auto_indent();
}); });
menu.action_group->add(Gtk::Action::create("SourceGotoLine", "Go to Line"), Gtk::AccelKey(menu.key_map["source_goto_line"]), [this]() {
menu->add_action("source_goto_line", [this]() {
goto_line_entry(); goto_line_entry();
}); });
menu.action_group->add(Gtk::Action::create("SourceCenterCursor", "Center Cursor"), Gtk::AccelKey(menu.key_map["source_center_cursor"]), [this]() { menu->add_action("source_center_cursor", [this]() {
if(notebook.get_current_page()!=-1) { if(notebook.get_current_page()!=-1) {
while(gtk_events_pending()) while(gtk_events_pending())
gtk_main_iteration(); gtk_main_iteration();
@ -349,32 +336,8 @@ void Window::create_menu() {
notebook.get_current_view()->scroll_to(notebook.get_current_view()->get_buffer()->get_insert(), 0.0, 1.0, 0.5); notebook.get_current_view()->scroll_to(notebook.get_current_view()->get_buffer()->get_insert(), 0.0, 1.0, 0.5);
} }
}); });
menu.action_group->add(Gtk::Action::create("SourceGotoDeclaration", "Go to Declaration"), Gtk::AccelKey(menu.key_map["source_goto_declaration"]), [this]() {
if(notebook.get_current_page()!=-1) { menu->add_action("source_find_documentation", [this]() {
if(notebook.get_current_view()->get_declaration_location) {
auto location=notebook.get_current_view()->get_declaration_location();
if(location.first.size()>0) {
notebook.open(location.first);
notebook.get_current_view()->get_buffer()->place_cursor(notebook.get_current_view()->get_buffer()->get_iter_at_line_index(location.second.line-1, location.second.index-1));
while(gtk_events_pending())
gtk_main_iteration();
if(notebook.get_current_page()!=-1)
notebook.get_current_view()->scroll_to(notebook.get_current_view()->get_buffer()->get_insert(), 0.0, 1.0, 0.5);
}
}
}
});
menu.action_group->add(Gtk::Action::create("SourceGotoMethod", "Go to Method"), Gtk::AccelKey(menu.key_map["source_goto_method"]), [this]() {
if(notebook.get_current_page()!=-1) {
if(notebook.get_current_view()->goto_method) {
notebook.get_current_view()->goto_method();
}
}
});
menu.action_group->add(Gtk::Action::create("SourceRename", "Rename"), Gtk::AccelKey(menu.key_map["source_rename"]), [this]() {
rename_token_entry();
});
menu.action_group->add(Gtk::Action::create("SourceFindDocumentation", "Find Documentation"), Gtk::AccelKey(menu.key_map["source_find_documentation"]), [this]() {
if(notebook.get_current_page()!=-1) { if(notebook.get_current_page()!=-1) {
if(notebook.get_current_view()->get_token_data) { if(notebook.get_current_view()->get_token_data) {
auto data=notebook.get_current_view()->get_token_data(); auto data=notebook.get_current_view()->get_token_data();
@ -414,22 +377,61 @@ void Window::create_menu() {
} }
} }
}); });
menu.action_group->add(Gtk::Action::create("SourceGotoNextDiagnostic", "Go to next Diagnostic"), Gtk::AccelKey(menu.key_map["source_goto_next_diagnostic"]), [this]() {
menu->add_action("source_goto_declaration", [this]() {
if(notebook.get_current_page()!=-1) {
if(notebook.get_current_view()->get_declaration_location) {
auto location=notebook.get_current_view()->get_declaration_location();
if(location.first.size()>0) {
notebook.open(location.first);
auto line=static_cast<int>(location.second.line)-1;
auto index=static_cast<int>(location.second.index)-1;
auto buffer=notebook.get_current_view()->get_buffer();
line=std::min(line, buffer->get_line_count()-1);
if(line>=0) {
auto iter=buffer->get_iter_at_line(line);
while(!iter.ends_line())
iter.forward_char();
auto end_line_index=iter.get_line_index();
index=std::min(index, end_line_index);
buffer->place_cursor(buffer->get_iter_at_line_index(line, index));
while(gtk_events_pending())
gtk_main_iteration();
if(notebook.get_current_page()!=-1)
notebook.get_current_view()->scroll_to(notebook.get_current_view()->get_buffer()->get_insert(), 0.0, 1.0, 0.5);
}
}
}
}
});
menu->add_action("source_goto_method", [this]() {
if(notebook.get_current_page()!=-1) {
if(notebook.get_current_view()->goto_method) {
notebook.get_current_view()->goto_method();
}
}
});
menu->add_action("source_rename", [this]() {
rename_token_entry();
});
menu->add_action("source_goto_next_diagnostic", [this]() {
if(notebook.get_current_page()!=-1) { if(notebook.get_current_page()!=-1) {
if(notebook.get_current_view()->goto_next_diagnostic) { if(notebook.get_current_view()->goto_next_diagnostic) {
notebook.get_current_view()->goto_next_diagnostic(); notebook.get_current_view()->goto_next_diagnostic();
} }
} }
}); });
menu.action_group->add(Gtk::Action::create("SourceApplyFixIts", "Apply Fix-Its"), Gtk::AccelKey(menu.key_map["source_apply_fix_its"]), [this]() { menu->add_action("source_apply_fix_its", [this]() {
if(notebook.get_current_page()!=-1) { if(notebook.get_current_page()!=-1) {
if(notebook.get_current_view()->apply_fix_its) { if(notebook.get_current_view()->apply_fix_its) {
notebook.get_current_view()->apply_fix_its(); notebook.get_current_view()->apply_fix_its();
} }
} }
}); });
menu.action_group->add(Gtk::Action::create("ProjectCompileAndRun", "Compile and Run"), Gtk::AccelKey(menu.key_map["compile_and_run"]), [this]() { menu->add_action("compile_and_run", [this]() {
if(notebook.get_current_page()==-1 || compiling) if(notebook.get_current_page()==-1 || compiling)
return; return;
CMake cmake(notebook.get_current_view()->file_path); CMake cmake(notebook.get_current_view()->file_path);
@ -469,7 +471,7 @@ void Window::create_menu() {
} }
} }
}); });
menu.action_group->add(Gtk::Action::create("ProjectCompile", "Compile"), Gtk::AccelKey(menu.key_map["compile"]), [this]() { menu->add_action("compile", [this]() {
if(notebook.get_current_page()==-1 || compiling) if(notebook.get_current_page()==-1 || compiling)
return; return;
CMake cmake(notebook.get_current_view()->file_path); CMake cmake(notebook.get_current_view()->file_path);
@ -481,7 +483,8 @@ void Window::create_menu() {
}); });
} }
}); });
menu.action_group->add(Gtk::Action::create("ProjectRunCommand", "Run Command"), Gtk::AccelKey(menu.key_map["run_command"]), [this]() {
menu->add_action("run_command", [this]() {
entry_box.clear(); entry_box.clear();
entry_box.labels.emplace_back(); entry_box.labels.emplace_back();
auto label_it=entry_box.labels.begin(); auto label_it=entry_box.labels.begin();
@ -502,7 +505,7 @@ void Window::create_menu() {
else else
run_path=Singleton::directories()->current_path; run_path=Singleton::directories()->current_path;
Singleton::terminal()->async_print("Running: "+content+'\n'); Singleton::terminal()->async_print("Running: "+content+'\n');
Singleton::terminal()->async_execute(content, run_path, [this, content](int exit_code){ Singleton::terminal()->async_execute(content, run_path, [this, content](int exit_code){
Singleton::terminal()->async_print(content+" returned: "+std::to_string(exit_code)+'\n'); Singleton::terminal()->async_print(content+" returned: "+std::to_string(exit_code)+'\n');
}); });
@ -516,29 +519,20 @@ void Window::create_menu() {
}); });
entry_box.show(); entry_box.show();
}); });
menu.action_group->add(Gtk::Action::create("ProjectKillLastRunning", "Kill Last Process"), Gtk::AccelKey(menu.key_map["kill_last_running"]), [this]() {
menu->add_action("kill_last_running", [this]() {
Singleton::terminal()->kill_last_async_execute(); Singleton::terminal()->kill_last_async_execute();
}); });
menu.action_group->add(Gtk::Action::create("ProjectForceKillLastRunning", "Force Kill Last Process"), Gtk::AccelKey(menu.key_map["force_kill_last_running"]), [this]() { menu->add_action("force_kill_last_running", [this]() {
Singleton::terminal()->kill_last_async_execute(true); Singleton::terminal()->kill_last_async_execute(true);
}); });
menu.action_group->add(Gtk::Action::create("WindowCloseTab", "Close Tab"), Gtk::AccelKey(menu.key_map["close_tab"]), [this]() {
notebook.close_current_page(); menu->add_action("next_tab", [this]() {
if(notebook.get_current_page()!=-1) {
notebook.get_current_view()->set_status(notebook.get_current_view()->status);
notebook.get_current_view()->set_info(notebook.get_current_view()->info);
}
else {
Singleton::status()->set_text("");
Singleton::info()->set_text("");
}
});
menu.action_group->add(Gtk::Action::create("WindowNextTab", "Next Tab"), Gtk::AccelKey(menu.key_map["next_tab"]), [this]() {
if(notebook.get_current_page()!=-1) { if(notebook.get_current_page()!=-1) {
notebook.open(notebook.get_view((notebook.get_current_page()+1)%notebook.size())->file_path); notebook.open(notebook.get_view((notebook.get_current_page()+1)%notebook.size())->file_path);
} }
}); });
menu.action_group->add(Gtk::Action::create("WindowPreviousTab", "Previous Tab"), Gtk::AccelKey(menu.key_map["previous_tab"]), [this]() { menu->add_action("previous_tab", [this]() {
if(notebook.get_current_page()!=-1) { if(notebook.get_current_page()!=-1) {
int previous_page=notebook.get_current_page()-1; int previous_page=notebook.get_current_page()-1;
if(previous_page<0) if(previous_page<0)
@ -546,10 +540,31 @@ void Window::create_menu() {
notebook.open(notebook.get_view(previous_page)->file_path); notebook.open(notebook.get_view(previous_page)->file_path);
} }
}); });
menu.action_group->add(Gtk::Action::create("HelpAbout", "About"), [this] () { menu->add_action("close_tab", [this]() {
about.show(); notebook.close_current_page();
about.present(); if(notebook.get_current_page()!=-1) {
notebook.get_current_view()->set_status(notebook.get_current_view()->status);
notebook.get_current_view()->set_info(notebook.get_current_view()->info);
}
else {
Singleton::status()->set_text("");
Singleton::info()->set_text("");
activate_menu_items(false);
}
}); });
activate_menu_items(false);
}
void Window::activate_menu_items(bool activate) {
auto menu = Singleton::menu();
menu->actions["source_indentation_auto_indent_buffer"]->set_enabled(activate ? static_cast<bool>(notebook.get_current_view()->auto_indent) : false);
menu->actions["source_find_documentation"]->set_enabled(activate ? static_cast<bool>(notebook.get_current_view()->get_token_data) : false);
menu->actions["source_goto_declaration"]->set_enabled(activate ? static_cast<bool>(notebook.get_current_view()->get_declaration_location) : false);
menu->actions["source_goto_method"]->set_enabled(activate ? static_cast<bool>(notebook.get_current_view()->goto_method) : false);
menu->actions["source_rename"]->set_enabled(activate ? static_cast<bool>(notebook.get_current_view()->rename_similar_tokens) : false);
menu->actions["source_goto_next_diagnostic"]->set_enabled(activate ? static_cast<bool>(notebook.get_current_view()->goto_next_diagnostic) : false);
menu->actions["source_apply_fix_its"]->set_enabled(activate ? static_cast<bool>(notebook.get_current_view()->apply_fix_its) : false);
} }
bool Window::on_key_press_event(GdkEventKey *event) { bool Window::on_key_press_event(GdkEventKey *event) {

10
src/window.h

@ -5,10 +5,9 @@
#include "directories.h" #include "directories.h"
#include "entrybox.h" #include "entrybox.h"
#include "notebook.h" #include "notebook.h"
#include "menu.h"
#include <atomic> #include <atomic>
class Window : public Gtk::Window { class Window : public Gtk::ApplicationWindow {
public: public:
Window(); Window();
Notebook notebook; Notebook notebook;
@ -18,7 +17,6 @@ public:
std::string theme_variant; std::string theme_variant;
std::string version; std::string version;
std::pair<int, int> default_size; std::pair<int, int> default_size;
boost::property_tree::ptree keybindings;
}; };
protected: protected:
@ -26,7 +24,6 @@ protected:
bool on_delete_event (GdkEventAny *event); bool on_delete_event (GdkEventAny *event);
private: private:
Gtk::Box box;
Gtk::VPaned vpaned; Gtk::VPaned vpaned;
Gtk::Paned directory_and_notebook_panes; Gtk::Paned directory_and_notebook_panes;
Gtk::VBox notebook_vbox; Gtk::VBox notebook_vbox;
@ -35,17 +32,16 @@ private:
Gtk::HBox info_and_status_hbox; Gtk::HBox info_and_status_hbox;
Gtk::AboutDialog about; Gtk::AboutDialog about;
EntryBox entry_box; EntryBox entry_box;
Menu menu;
std::atomic<bool> compiling; std::atomic<bool> compiling;
void configure(); void configure();
void create_menu(); void set_menu_actions();
void activate_menu_items(bool activate=true);
void hide(); void hide();
void search_and_replace_entry(); void search_and_replace_entry();
void set_tab_entry(); void set_tab_entry();
void goto_line_entry(); void goto_line_entry();
void rename_token_entry(); void rename_token_entry();
void generate_keybindings();
std::string last_search; std::string last_search;
std::string last_replace; std::string last_replace;
std::string last_run_command; std::string last_run_command;

Loading…
Cancel
Save