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. 39
      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. 394
      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. 21
      src/source.cc
  23. 2
      src/source.h
  24. 80
      src/source_clang.cc
  25. 24
      src/source_clang.h
  26. 100
      src/terminal.cc
  27. 4
      src/terminal.h
  28. 163
      src/terminal_win.cc
  29. 307
      src/window.cc
  30. 10
      src/window.h

3
.gitmodules vendored

@ -1,3 +1,4 @@
[submodule "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
* Regex search and replace
* Smart paste, keys and indentation
* Auto-indentation of C++ file buffers through [clang-format](http://clang.llvm.org/docs/ClangFormat.html)
* Source minimap
* Full UTF-8 support

14
docs/install.md

@ -15,6 +15,12 @@ make
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
Install dependencies:
```sh
@ -34,10 +40,16 @@ make
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/)
Install dependencies (installing llvm may take some time):
```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:

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")
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)
find_package(LibClang REQUIRED)

39
src/config.cc

@ -8,28 +8,23 @@
using namespace std; //TODO: remove
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
try {
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);
update_config_file();
retrieve_config();
}
catch(const std::exception &e) {
Singleton::terminal()->print("Error reading "+config_json + "config.json: "+e.what()+"\n");
std::stringstream ss;
ss << configjson;
boost::property_tree::read_json(ss, cfg);
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();
}
@ -63,7 +58,10 @@ void MainConfig::find_or_create_config_files() {
}
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();
GenerateDirectoryFilter();
@ -147,6 +145,8 @@ void MainConfig::GenerateSource() {
for (auto &i : source_json.get_child("clang_types"))
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");
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");
@ -167,7 +167,8 @@ void MainConfig::GenerateDirectoryFilter() {
for ( auto &i : ignore_json )
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;
char *ptr = nullptr;
for (auto &env : locations) {
@ -178,9 +179,17 @@ std::vector<std::string> MainConfig::init_home_path(){
if (boost::filesystem::exists(ptr)) {
home /= ptr;
home /= ".juci";
return locations;
break;
}
}
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);
}
home="";
return locations;
return;
}

3
src/config.h

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

2
src/dialogs.cc

@ -40,7 +40,7 @@ std::string Dialog::new_folder() {
}
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)},
Gtk::FILE_CHOOSER_ACTION_OPEN);
}

63
src/files.h

@ -1,6 +1,6 @@
#include <string>
#define JUCI_VERSION "0.9.3"
#define JUCI_VERSION "0.9.4"
#define JUCI_ENV_SEARCH_LOCATIONS {"AppData", "HOME", "JUCI_HOME"}
@ -13,24 +13,36 @@ const std::string configjson =
" },\n"
" \"terminal_history_size\": 1000,\n"
" \"gtk_theme\": {\n"
" \"name\": \"Adwaita\", //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_comment\": \"Use \\\"\\\" for default theme, At least these two exist on all systems: Adwaita, Raleigh\",\n"
" \"name\": \"Adwaita\",\n"
" \"variant_comment\": \"Use \\\"\\\" for default variant, and \\\"dark\\\" for dark theme variant\",\n"
" \"variant\": \"\"\n"
" },\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__
" \"font\": \"Menlo 11\", "
" \"font\": \"Menlo 11\",\n"
#else
#ifdef _WIN32
" \"font\": \"Consolas\", "
" \"font\": \"Consolas\",\n"
#else
" \"font\": \"Monospace\", "
" \"font\": \"Monospace\",\n"
#endif
#endif
"//Use \"\" for default font, and for instance \"Monospace 12\" to also set size.\n"
" \"show_map\": true,\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"
" \"8\": \"def:function\",\n"
" \"21\": \"def:function\",\n"
@ -45,40 +57,36 @@ const std::string configjson =
" \"702\": \"def:statement\",\n"
" \"705\": \"def:comment\"\n"
" },\n"
" \"auto_tab_char_and_size\": true, //Use false to always use default tab char and size\n"
" \"default_tab_char\": \" \", //Use \"\\t\" for regular tab\n"
" \"default_tab_size\": 2,\n"
" \"wrap_lines\": false,\n"
" \"highlight_current_line\": true,\n"
" \"show_line_numbers\": true\n"
" \"clang_format_style_comment\": \"IndentWidth, AccessModifierOffset and UseTab are set automatically. See http://clang.llvm.org/docs/ClangFormatStyleOptions.html\",\n"
" \"clang_format_style\": \"ColumnLimit: 0\"\n"
" },\n"
" \"keybindings\": {\n"
" \"preferences\": \"<primary>comma\",\n"
" \"quit\": \"<primary>q\",\n"
" \"new_file\": \"<primary>n\",\n"
" \"new_folder\": \"<primary><shift>n\",\n"
" \"open_folder\": \"<primary><shift>o\",\n"
" \"open_file\": \"<primary>o\",\n"
" \"open_folder\": \"<primary><shift>o\",\n"
" \"save\": \"<primary>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_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_set_tab\": \"\",\n"
" \"source_spellcheck\": \"\",\n"
" \"source_spellcheck_clear\": \"\",\n"
" \"source_spellcheck_next_error\": \"<primary><shift>e\",\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_center_cursor\": \"<primary>l\",\n"
" \"source_find_documentation\": \"<primary><shift>d\",\n"
" \"source_goto_declaration\": \"<primary>d\",\n"
" \"source_goto_method\": \"<primary>m\",\n"
" \"source_rename\": \"<primary>r\",\n"
" \"source_find_documentation\": \"<primary><shift>d\",\n"
" \"source_goto_next_diagnostic\": \"<primary>e\",\n"
" \"source_apply_fix_its\": \"<control>space\",\n"
" \"compile_and_run\": \"<primary>Return\",\n"
@ -139,10 +147,11 @@ const std::string juci_light_style =
" <color name=\"purple\" value=\"#990099\"/>\n"
"\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"
"\n"
" <!-- Current Line Highlighting -->\n"
" <style name=\"current-line\" background=\"#EEEEEE\"/>\n"
" <style name=\"current-line\" background=\"#rgba(0,0,0,.07)\"/>\n"
"\n"
" <!-- Bracket Matching -->\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"
"\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"
"\n"
" <!-- Current Line Highlighting -->\n"
" <style name=\"current-line\" background=\"#333333\"/>\n"
" <style name=\"current-line\" background=\"#rgba(255,255,255,.06)\"/>\n"
"\n"
" <!-- Bracket Matching -->\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"
"\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"
"\n"
" <!-- Current Line Highlighting -->\n"
" <style name=\"current-line\" background=\"blue\"/>\n"
" <style name=\"current-line\" background=\"#rgba(255,255,255,.05)\"/>\n"
"\n"
" <!-- Bracket Matching -->\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](){
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();
}
@ -67,8 +67,30 @@ void app::on_activate() {
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) {
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[]) {

1
src/juci.h

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

394
src/menu.cc

@ -1,106 +1,322 @@
#include "menu.h"
#include "singletons.h"
#include <string>
#include <iostream>
using namespace std; //TODO: remove
Menu::Menu() {
action_group = Gtk::ActionGroup::create();
ui_manager = Gtk::UIManager::create();
ui_manager->insert_action_group(action_group);
}
action_group->add(Gtk::Action::create("FileMenu", "File"));
action_group->add(Gtk::Action::create("EditMenu", "Edit"));
action_group->add(Gtk::Action::create("WindowMenu", "_Window"));
action_group->add(Gtk::Action::create("ProjectMenu", "P_roject"));
action_group->add(Gtk::Action::create("SourceMenu", "_Source"));
action_group->add(Gtk::Action::create("PluginMenu", "_Plugins"));
action_group->add(Gtk::Action::create("HelpMenu", "Help"));
//TODO: if Ubuntu ever gets fixed, move to constructor, also cleanup the rest of the Ubuntu specific code
void Menu::init() {
auto accels=Singleton::Config::menu()->keys;
for(auto &accel: accels) {
#ifdef UBUNTU_BUGGED_MENU
size_t pos=0;
std::string second=accel.second;
while((pos=second.find('<', pos))!=std::string::npos) {
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>\n"
" <menubar name=\"MenuBar\">\n"
" <menu action=\"FileMenu\">\n"
" <menuitem action=\"FileNewFile\"/>\n"
" <menuitem action=\"FileNewFolder\"/>\n"
" <menu action=\"FileNewProject\">\n"
" <menuitem action=\"FileNewProjectCpp\"/>\n"
" </menu>\n"
" <separator/>\n"
" <menuitem action=\"FileOpenFile\"/>\n"
" <menuitem action=\"FileOpenFolder\"/>\n"
" <separator/>\n"
" <menuitem action=\"FileSave\"/>\n"
" <menuitem action=\"FileSaveAs\"/>\n"
" <separator/>\n"
" <menuitem action=\"Preferences\"/>\n"
" <separator/>\n"
" <menuitem action=\"FileQuit\"/>\n"
" </menu>\n"
" <menu action=\"EditMenu\">\n"
" <menuitem action=\"EditUndo\"/>\n"
" <menuitem action=\"EditRedo\"/>\n"
" <separator/>\n"
" <menuitem action=\"EditCopy\"/>\n"
" <menuitem action=\"EditCut\"/>\n"
" <menuitem action=\"EditPaste\"/>\n"
" <separator/>\n"
" <menuitem action=\"EditFind\"/>\n"
" </menu>\n"
" <menu action=\"SourceMenu\">\n"
" <menu action=\"SourceSpellCheck\">\n"
" <menuitem action=\"SourceSpellCheckBuffer\"/>\n"
" <menuitem action=\"SourceSpellCheckClear\"/>\n"
" <menuitem action=\"SourceSpellCheckNextError\"/>\n"
" </menu>\n"
" <separator/>\n"
" <menu action=\"SourceIndentation\">\n"
" <menuitem action=\"SourceIndentationSetBufferTab\"/>\n"
" <menuitem action=\"SourceIndentationAutoIndentBuffer\"/>\n"
" </menu>\n"
" <separator/>\n"
" <menuitem action=\"SourceGotoLine\"/>\n"
" <menuitem action=\"SourceCenterCursor\"/>\n"
" <separator/>\n"
" <menuitem action=\"SourceFindDocumentation\"/>\n"
" <separator/>\n"
" <menuitem action=\"SourceGotoDeclaration\"/>\n"
" <menuitem action=\"SourceGotoMethod\"/>\n"
" <menuitem action=\"SourceRename\"/>\n"
" <separator/>\n"
" <menuitem action=\"SourceGotoNextDiagnostic\"/>\n"
" <menuitem action=\"SourceApplyFixIts\"/>\n"
" <separator/>\n"
" </menu>\n"
" <menu action=\"ProjectMenu\">\n"
" <menuitem action=\"ProjectCompileAndRun\"/>\n"
" <menuitem action=\"ProjectCompile\"/>\n"
" <separator/>\n"
" <menuitem action=\"ProjectRunCommand\"/>\n"
" <menuitem action=\"ProjectKillLastRunning\"/>\n"
" <menuitem action=\"ProjectForceKillLastRunning\"/>\n"
" </menu>\n"
" <menu action=\"WindowMenu\">\n"
" <menuitem action=\"WindowNextTab\"/>\n"
" <menuitem action=\"WindowPreviousTab\"/>\n"
" <separator/>\n"
" <menuitem action=\"WindowCloseTab\"/>\n"
" </menu>\n"
" <menu action=\"PluginMenu\">\n"
" </menu>\n"
" <menu action=\"HelpMenu\">\n"
" <menuitem action=\"HelpAbout\"/>\n"
" </menu>\n"
" </menubar>\n"
"</ui>\n";
"<interface>"
" <menu id='juci-menu'>"
" <section>"
" <item>"
" <attribute name='label' translatable='yes'>_About</attribute>"
" <attribute name='action'>app.about</attribute>"
+accels["about"]+ //For Ubuntu...
" </item>"
" </section>"
" <section>"
" <item>"
" <attribute name='label' translatable='yes'>_Preferences</attribute>"
" <attribute name='action'>app.preferences</attribute>"
+accels["preferences"]+ //For Ubuntu...
" </item>"
" </section>"
" <section>"
" <item>"
" <attribute name='label' translatable='yes'>_Quit</attribute>"
" <attribute name='action'>app.quit</attribute>"
+accels["quit"]+ //For Ubuntu...
" </item>"
" </section>"
" </menu>"
""
" <menu id='window-menu'>"
" <submenu>"
" <attribute name='label' translatable='yes'>_File</attribute>"
" <section>"
" <item>"
" <attribute name='label' translatable='yes'>_New _File</attribute>"
" <attribute name='action'>app.new_file</attribute>"
+accels["new_file"]+ //For Ubuntu...
" </item>"
" <item>"
" <attribute name='label' translatable='yes'>_New _Directory</attribute>"
" <attribute name='action'>app.new_folder</attribute>"
+accels["new_folder"]+ //For Ubuntu...
" </item>"
" <submenu>"
" <attribute name='label' translatable='yes'>_New _Project</attribute>"
" <item>"
" <attribute name='label' translatable='no'>C++</attribute>"
" <attribute name='action'>app.new_project_cpp</attribute>"
+accels["new_project_cpp"]+ //For Ubuntu...
" </item>"
" </submenu>"
" </section>"
" <section>"
" <item>"
" <attribute name='label' translatable='yes'>_Open _File</attribute>"
" <attribute name='action'>app.open_file</attribute>"
+accels["open_file"]+ //For Ubuntu...
" </item>"
" <item>"
" <attribute name='label' translatable='yes'>_Open _Folder</attribute>"
" <attribute name='action'>app.open_folder</attribute>"
+accels["open_folder"]+ //For Ubuntu...
" </item>"
" </section>"
" <section>"
" <item>"
" <attribute name='label' translatable='yes'>_Save</attribute>"
" <attribute name='action'>app.save</attribute>"
+accels["save"]+ //For Ubuntu...
" </item>"
" <item>"
" <attribute name='label' translatable='yes'>_Save _As</attribute>"
" <attribute name='action'>app.save_as</attribute>"
+accels["save_as"]+ //For Ubuntu...
" </item>"
" </section>"
" </submenu>"
""
" <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() {
return *ui_manager->get_widget("/MenuBar");
void Menu::add_action(const std::string &name, std::function<void()> action) {
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() {
builder = Gtk::Builder::create();
try {
ui_manager->add_ui_from_string(ui_xml);
builder->add_from_string(ui_xml);
}
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 {
public:
class Config {
public:
std::unordered_map<std::string, std::string> keys;
};
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();
Glib::RefPtr<Gtk::Builder> builder;
std::unordered_map<std::string, std::string> key_map;
std::string ui_xml;
Glib::RefPtr<Gtk::UIManager> ui_manager;
Glib::RefPtr<Gtk::ActionGroup> action_group;
};
#endif // JUCI_MENU_H_

25
src/notebook.cc

@ -5,7 +5,7 @@
#include <regex>
#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"
#endif
@ -26,8 +26,12 @@ namespace sigc {
#endif
}
Notebook::Notebook() : Gtk::Notebook() {
Notebook::Notebook() : Gtk::Notebook(), last_index(-1) {
Gsv::init();
signal_switch_page().connect([this](Gtk::Widget* page, guint page_num) {
last_index=-1;
});
}
int Notebook::size() {
@ -102,7 +106,7 @@ void Notebook::open(const boost::filesystem::path &file_path) {
scrolled_windows.back()->add(*source_views.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()));
gtk_source_map_set_view(GTK_SOURCE_MAP(source_maps.back()->gobj()), source_views.back()->gobj());
#endif
@ -113,7 +117,13 @@ void Notebook::open(const boost::filesystem::path &file_path) {
set_tab_reorderable(*hboxes.back(), true);
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);
last_index=last_index_tmp;
set_focus_child(*source_views.back());
get_current_view()->get_buffer()->set_modified(false);
get_current_view()->grab_focus();
@ -138,7 +148,7 @@ void Notebook::open(const boost::filesystem::path &file_path) {
}
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_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);
@ -228,8 +238,13 @@ bool Notebook::close_current_page() {
}
int page = get_current_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);
#if GTK_VERSION_GE(3, 18)
#if GTKSOURCEVIEWMM_MAJOR_VERSION > 2 & GTKSOURCEVIEWMM_MINOR_VERSION > 17
source_maps.erase(source_maps.begin()+index);
#endif
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::ScrolledWindow> > scrolled_windows;
std::vector<std::unique_ptr<Gtk::HBox> > hboxes;
size_t last_index;
};
#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<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<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<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() {
if(!terminal_)
terminal_=std::unique_ptr<Terminal>(new Terminal());
return terminal_.get();
}
std::unique_ptr<Directories> Singleton::directories_=std::unique_ptr<Directories>();
Directories *Singleton::directories() {
if(!directories_)
directories_=std::unique_ptr<Directories>(new Directories());
return directories_.get();
}
std::unique_ptr<Window> Singleton::window_=std::unique_ptr<Window>();
Window *Singleton::window() {
if(!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());
return status_.get();
}
std::unique_ptr<Gtk::Label> Singleton::info_=std::unique_ptr<Gtk::Label>();
Gtk::Label *Singleton::info() {
if(!info_)
@ -40,3 +44,9 @@ Gtk::Label *Singleton::info() {
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 Window::Config *window() { return window_.get(); }
static Terminal::Config *terminal() {return terminal_.get();}
static Menu::Config *menu() {return menu_.get();}
static MainConfig *main() { return main_.get(); }
private:
@ -28,12 +29,14 @@ public:
static std::unique_ptr<Window::Config> window_;
static std::unique_ptr<Directories::Config> directories_;
static std::unique_ptr<Terminal::Config> terminal_;
static std::unique_ptr<Menu::Config> menu_;
static std::unique_ptr<MainConfig> main_;
};
static Terminal *terminal();
static Directories *directories();
static Gtk::Label *status();
static Gtk::Label *info();
static Menu *menu();
static Window *window();
private:
@ -41,6 +44,7 @@ private:
static std::unique_ptr<Gtk::Label> status_;
static std::unique_ptr<Gtk::Label> info_;
static std::unique_ptr<Directories> directories_;
static std::unique_ptr<Menu> menu_;
static std::unique_ptr<Window> window_;
};

21
src/source.cc

@ -314,6 +314,9 @@ void Source::View::configure() {
property_show_line_numbers() = Singleton::Config::source()->show_line_numbers;
if(Singleton::Config::source()->font.size()>0)
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:
auto scheme = get_source_buffer()->get_style_scheme();
@ -350,11 +353,9 @@ void Source::View::configure() {
error_property=style->property_background().get_value();
diagnostic_tag_underline->property_underline()=Pango::Underline::UNDERLINE_ERROR;
auto tag_class=G_OBJECT_GET_CLASS(diagnostic_tag_underline->gobj()); //For older GTK+ 3 versions:
auto param_spec=g_object_class_find_property(tag_class, "underline-rgba");
if(param_spec!=NULL) {
#if GTK_VERSION_GE(3, 16)
diagnostic_tag_underline->set_property("underline-rgba", Gdk::RGBA(error_property));
}
#endif
}
//TODO: clear tag_class and param_spec?
@ -1021,24 +1022,22 @@ bool Source::View::on_key_press_event(GdkEventKey* key) {
auto line_it = get_source_buffer()->get_iter_at_line(line_nr);
if(!get_buffer()->get_has_selection() || line_it!=selection_end) {
auto tabs_end_iter=get_tabs_end_iter(line_nr);
if(tabs_end_iter.starts_line() && tabs_end_iter.ends_line())
ignore_line.push_back(true);
else {
auto line_tabs=get_line_before(tabs_end_iter);
if(line_tabs.size()>0 || tabs_end_iter.ends_line()) {
if(!tabs_end_iter.ends_line()) {
if(line_tabs.size()>0) {
indent_left_steps=std::min(indent_left_steps, static_cast<unsigned>(line_tabs.size()));
ignore_line.push_back(false);
}
else if(static_cast<unsigned>(line_tabs.size())<indent_left_steps)
ignore_line.push_back(true);
else
ignore_line.push_back(false);
}
else {
get_source_buffer()->end_user_action();
return true;
}
}
}
}
for(int line_nr=line_start;line_nr<=line_end;line_nr++) {
Gtk::TextIter line_it = get_source_buffer()->get_iter_at_line(line_nr);

2
src/source.h

@ -36,6 +36,7 @@ namespace Source {
bool highlight_current_line;
bool show_line_numbers;
std::unordered_map<std::string, std::string> clang_types;
std::string clang_format_style;
std::unordered_map<std::string, DocumentationSearch> documentation_searches;
};
@ -100,6 +101,7 @@ namespace Source {
boost::filesystem::path project_path;
Glib::RefPtr<Gsv::Language> language;
std::function<void()> auto_indent;
std::function<std::pair<std::string, Offset>()> get_declaration_location;
std::function<void()> goto_method;
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());
//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:
parse_start.connect([this]{
parse_start_connection=parse_start.connect([this]{
if(parse_thread_buffer_map_mutex.try_lock()) {
parse_thread_buffer_map=get_buffer_map();
parse_thread_mapped=true;
@ -43,7 +43,7 @@ Source::View(file_path, project_path, language), parse_error(false) {
}
parse_thread_go=true;
});
parse_done.connect([this](){
parse_done_connection=parse_done.connect([this](){
if(parse_thread_mapped) {
if(parsing_mutex.try_lock()) {
update_syntax();
@ -58,7 +58,7 @@ Source::View(file_path, project_path, language), parse_error(false) {
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");
set_status("");
set_info("");
@ -105,10 +105,6 @@ void Source::ClangViewParse::configure() {
no_bracket_no_para_statement_regex=std::regex("^([ \\t]*)(else|try|do) *$");
}
Source::ClangViewParse::~ClangViewParse() {
delayed_reparse_connection.disconnect();
}
void Source::ClangViewParse::init_parse() {
type_tooltips.hide();
diagnostic_tooltips.hide();
@ -659,9 +655,10 @@ Source::ClangViewParse(file_path, project_path, language), autocomplete_cancel_s
autocomplete_cancel_starting=false;
});
do_delete_object.connect([this](){
do_delete_object_connection=do_delete_object.connect([this](){
if(delete_thread.joinable())
delete_thread.join();
do_delete_object_connection.disconnect();
delete this;
});
do_restart_parse.connect([this](){
@ -874,8 +871,6 @@ std::vector<Source::ClangViewAutocomplete::AutoCompleteData> Source::ClangViewAu
void Source::ClangViewAutocomplete::async_delete() {
parsing_in_progress->cancel("canceled, freeing resources in the background");
autocomplete_done_connection.disconnect();
autocomplete_fail_connection.disconnect();
parse_thread_stop=true;
delete_thread=std::thread([this](){
//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 {
if(source_readable) {
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) {
if(language) {
get_source_buffer()->set_highlight_syntax(true);
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();
void configure();
virtual void configure();
void start_reparse();
bool reparse_needed=false;
@ -39,8 +38,8 @@ namespace Source {
std::atomic<bool> parse_thread_stop;
std::atomic<bool> parse_error;
void show_diagnostic_tooltips(const Gdk::Rectangle &rectangle);
void show_type_tooltips(const Gdk::Rectangle &rectangle);
virtual void show_diagnostic_tooltips(const Gdk::Rectangle &rectangle);
virtual void show_type_tooltips(const Gdk::Rectangle &rectangle);
std::regex bracket_regex;
std::regex no_bracket_statement_regex;
@ -48,6 +47,10 @@ namespace Source {
std::set<int> diagnostic_offsets;
std::vector<FixIt> fix_its;
sigc::connection parse_done_connection;
sigc::connection parse_start_connection;
sigc::connection parse_fail_connection;
private:
std::map<std::string, std::string> get_buffer_map() const;
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);
void async_delete();
virtual void async_delete();
bool restart_parse();
protected:
bool on_key_press_event(GdkEventKey* key);
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:
void start_autocomplete();
void autocomplete();
@ -89,9 +96,7 @@ namespace Source {
bool completion_dialog_shown=false;
std::vector<AutoCompleteData> get_autocomplete_suggestions(int line_number, int column, std::map<std::string, std::string>& buffer_map);
Glib::Dispatcher autocomplete_done;
sigc::connection autocomplete_done_connection;
Glib::Dispatcher autocomplete_fail;
sigc::connection autocomplete_fail_connection;
bool autocomplete_starting=false;
std::atomic<bool> autocomplete_cancel_starting;
guint last_keyval=0;
@ -108,13 +113,13 @@ namespace Source {
class ClangViewRefactor : public ClangViewAutocomplete {
public:
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:
std::list<std::pair<Glib::RefPtr<Gtk::TextMark>, Glib::RefPtr<Gtk::TextMark> > > similar_token_marks;
void tag_similar_tokens(const Token &token);
Glib::RefPtr<Gtk::TextTag> similar_tokens_tag;
Token last_tagged_token;
sigc::connection delayed_tag_similar_tokens_connection;
std::unique_ptr<SelectionDialog> selection_dialog;
bool renaming=false;
};
@ -122,6 +127,7 @@ namespace Source {
class ClangView : public ClangViewRefactor {
public:
ClangView(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path, Glib::RefPtr<Gsv::Language> language);
virtual void async_delete();
};
}

100
src/terminal.cc

@ -8,6 +8,8 @@
#include <iostream> //TODO: remove
using namespace std; //TODO: remove
const ssize_t buffer_size=131072;
//A working implementation of popen3, with all pipes getting closed properly.
//TODO: Eidheim is going to publish this one on his github, along with example uses
pid_t popen3(const std::string &command, const std::string &path, int *stdin_fd, int *stdout_fd, int *stderr_fd) {
@ -144,21 +146,26 @@ Terminal::Terminal() {
});
}
int Terminal::execute(const std::string &command, const boost::filesystem::path &path) {
JDEBUG("start");
int Terminal::execute(const std::string &command, const boost::filesystem::path &path, bool use_pipes) {
int stdin_fd, stdout_fd, stderr_fd;
auto pid=popen3(command, path.string(), &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[1024];
char buffer[buffer_size];
ssize_t n;
while ((n=read(stderr_fd, buffer, 1024)) > 0) {
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);
@ -166,31 +173,94 @@ int Terminal::execute(const std::string &command, const boost::filesystem::path
});
stderr_thread.detach();
std::thread stdout_thread([this, stdout_fd](){
char buffer[1024];
char buffer[buffer_size];
ssize_t n;
while ((n=read(stdout_fd, buffer, 1024)) > 0) {
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;
auto pid=popen3(command, path.string(), &stdin_fd, &stdout_fd, &stderr_fd);
if (pid<=0) {
async_print("Error: Failed to run command: " + command + "\n");
return -1;
}
else {
std::thread stderr_thread([this, stderr_fd](){
char buffer[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_stream, stdout_fd](){
char buffer[buffer_size];
ssize_t n;
while ((n=read(stdout_fd, buffer, buffer_size)) > 0) {
Glib::ustring umessage;
umessage.reserve(n);
for(ssize_t c=0;c<n;c++)
umessage+=buffer[c];
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();
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;
waitpid(pid, &exit_code, 0);
close(stdout_fd);
close(stderr_fd);
JDEBUG("end");
return exit_code;
}
}
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](){
JDEBUG("start");
int stdin_fd, stdout_fd, stderr_fd;
async_executes_mutex.lock();
stdin_buffer.clear();
@ -205,10 +275,11 @@ void Terminal::async_execute(const std::string &command, const boost::filesystem
}
else {
std::thread stderr_thread([this, stderr_fd](){
char buffer[1024];
char buffer[buffer_size];
ssize_t n;
while ((n=read(stderr_fd, buffer, 1024)) > 0) {
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);
@ -216,10 +287,11 @@ void Terminal::async_execute(const std::string &command, const boost::filesystem
});
stderr_thread.detach();
std::thread stdout_thread([this, stdout_fd](){
char buffer[1024];
char buffer[buffer_size];
ssize_t n;
while ((n=read(stdout_fd, buffer, 1024)) > 0) {
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);
@ -244,8 +316,6 @@ void Terminal::async_execute(const std::string &command, const boost::filesystem
if(callback)
callback(exit_code);
JDEBUG("end");
}
});
async_execute_thread.detach();

4
src/terminal.h

@ -8,6 +8,7 @@
#include <thread>
#include <atomic>
#include <list>
#include <iostream>
class Terminal : public Gtk::TextView {
public:
@ -33,7 +34,8 @@ public:
};
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 kill_last_async_execute(bool force=false);
void kill_async_executes(bool force=false);

163
src/terminal_win.cc

@ -8,8 +8,11 @@
#include <iostream> //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 g_hChildStd_IN_Rd = NULL;
HANDLE g_hChildStd_IN_Wr = NULL;
@ -24,6 +27,7 @@ HANDLE popen3(const std::string &command, const std::string &path, HANDLE *stdin
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
if(stdin_h!=nullptr) {
if (!CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0))
return NULL;
if(!SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0)) {
@ -31,34 +35,39 @@ HANDLE popen3(const std::string &command, const std::string &path, HANDLE *stdin
CloseHandle(g_hChildStd_IN_Wr);
return NULL;
}
}
if(stdout_h!=nullptr) {
if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0)) {
CloseHandle(g_hChildStd_IN_Rd);
CloseHandle(g_hChildStd_IN_Wr);
if(stdin_h!=nullptr) CloseHandle(g_hChildStd_IN_Rd);
if(stdin_h!=nullptr) 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);
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(stderr_h!=nullptr) {
if (!CreatePipe(&g_hChildStd_ERR_Rd, &g_hChildStd_ERR_Wr, &saAttr, 0)) {
CloseHandle(g_hChildStd_IN_Rd);
CloseHandle(g_hChildStd_IN_Wr);
CloseHandle(g_hChildStd_OUT_Rd);
CloseHandle(g_hChildStd_OUT_Wr);
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);
return NULL;
}
if(!SetHandleInformation(g_hChildStd_ERR_Rd, HANDLE_FLAG_INHERIT, 0)) {
CloseHandle(g_hChildStd_IN_Rd);
CloseHandle(g_hChildStd_IN_Wr);
CloseHandle(g_hChildStd_OUT_Rd);
CloseHandle(g_hChildStd_OUT_Wr);
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;
STARTUPINFO siStartInfo;
@ -67,9 +76,10 @@ HANDLE popen3(const std::string &command, const std::string &path, HANDLE *stdin
ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = g_hChildStd_ERR_Wr;
siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
siStartInfo.hStdInput = g_hChildStd_IN_Rd;
if(stdin_h!=nullptr) siStartInfo.hStdInput = g_hChildStd_IN_Rd;
if(stdout_h!=nullptr) siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
if(stderr_h!=nullptr) siStartInfo.hStdError = g_hChildStd_ERR_Wr;
if(stdin_h!=nullptr || stdout_h!=nullptr || stderr_h!=nullptr)
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
char* path_ptr;
@ -95,9 +105,9 @@ HANDLE popen3(const std::string &command, const std::string &path, HANDLE *stdin
if(!bSuccess) {
CloseHandle(process_info.hProcess);
CloseHandle(process_info.hThread);
CloseHandle(g_hChildStd_IN_Rd);
CloseHandle(g_hChildStd_OUT_Wr);
CloseHandle(g_hChildStd_ERR_Wr);
if(stdin_h!=nullptr) CloseHandle(g_hChildStd_IN_Rd);
if(stdout_h!=nullptr) CloseHandle(g_hChildStd_OUT_Wr);
if(stderr_h!=nullptr) CloseHandle(g_hChildStd_ERR_Wr);
return NULL;
}
else {
@ -106,14 +116,14 @@ HANDLE popen3(const std::string &command, const std::string &path, HANDLE *stdin
// of the child process, for example.
CloseHandle(process_info.hThread);
CloseHandle(g_hChildStd_IN_Rd);
CloseHandle(g_hChildStd_OUT_Wr);
CloseHandle(g_hChildStd_ERR_Wr);
if(stdin_h!=nullptr) CloseHandle(g_hChildStd_IN_Rd);
if(stdout_h!=nullptr) CloseHandle(g_hChildStd_OUT_Wr);
if(stderr_h!=nullptr) CloseHandle(g_hChildStd_ERR_Wr);
}
*stdin_h=g_hChildStd_IN_Wr;
*stdout_h=g_hChildStd_OUT_Rd;
*stderr_h=g_hChildStd_ERR_Rd;
if(stdin_h!=NULL) *stdin_h=g_hChildStd_IN_Wr;
if(stdout_h!=NULL) *stdout_h=g_hChildStd_OUT_Rd;
if(stderr_h!=NULL) *stderr_h=g_hChildStd_ERR_Rd;
return process_info.hProcess;
}
@ -181,24 +191,29 @@ 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) {
int Terminal::execute(const std::string &command, const boost::filesystem::path &path, bool use_pipes) {
HANDLE stdin_h, stdout_h, stderr_h;
auto process=popen3(command, path.string(), &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[BUFSIZE];
CHAR buffer[buffer_size];
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)
break;
std::string message;
message.reserve(n);
for(DWORD c=0;c<n;c++)
message+=buffer[c];
async_print(message, true);
@ -208,26 +223,100 @@ int Terminal::execute(const std::string &command, const boost::filesystem::path
std::thread stdout_thread([this, stdout_h](){
DWORD n;
CHAR buffer[BUFSIZE];
CHAR buffer[buffer_size];
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)
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;
auto process=popen3(command, path.string(), &stdin_h, &stdout_h, &stderr_h);
if(process==NULL) {
async_print("Error: Failed to run command: " + command + "\n");
return -1;
}
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_stream, 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;
Glib::ustring umessage;
umessage.reserve(n);
for(DWORD c=0;c<n;c++)
umessage+=buffer[c];
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();
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;
WaitForSingleObject(process, INFINITE);
GetExitCodeProcess(process, &exit_code);
CloseHandle(process);
CloseHandle(stdout_h);
CloseHandle(stderr_h);
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](){
DWORD n;
CHAR buffer[BUFSIZE];
CHAR buffer[buffer_size];
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)
break;
std::string message;
message.reserve(n);
for(DWORD c=0;c<n;c++)
message+=buffer[c];
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](){
DWORD n;
CHAR buffer[BUFSIZE];
CHAR buffer[buffer_size];
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)
break;
std::string message;
message.reserve(n);
for(DWORD c=0;c<n;c++)
message+=buffer[c];
async_print(message);

307
src/window.cc

@ -22,30 +22,17 @@ namespace sigc {
#endif
}
void Window::generate_keybindings() {
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) {
Window::Window() : compiling(false) {
JDEBUG("start");
set_title("juCi++");
set_events(Gdk::POINTER_MOTION_MASK|Gdk::FOCUS_CHANGE_MASK|Gdk::SCROLL_MASK);
set_menu_actions();
configure();
set_default_size(Singleton::Config::window()->default_size.first, Singleton::Config::window()->default_size.second);
//PluginApi(&this->notebook, &this->menu);
add(box);
//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);
add(vpaned);
directory_and_notebook_panes.pack1(*Singleton::directories(), Gtk::SHRINK);
notebook_vbox.pack_start(notebook);
@ -63,7 +50,6 @@ Window::Window() : box(Gtk::ORIENTATION_VERTICAL), compiling(false) {
terminal_vbox.pack_end(info_and_status_hbox, Gtk::PACK_SHRINK);
vpaned.pack2(terminal_vbox, true, true);
box.pack_end(vpaned);
show_all_children();
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](){
box.set_focus_chain({&vpaned});
vpaned.set_focus_chain({&directory_and_notebook_panes});
directory_and_notebook_panes.set_focus_chain({&notebook_vbox});
notebook_vbox.set_focus_chain({&entry_box});
});
entry_box.signal_hide().connect([this](){
box.unset_focus_chain();
vpaned.unset_focus_chain();
directory_and_notebook_panes.unset_focus_chain();
notebook_vbox.unset_focus_chain();
@ -104,23 +88,7 @@ Window::Window() : box(Gtk::ORIENTATION_VERTICAL), compiling(false) {
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")))
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);
activate_menu_items();
Singleton::directories()->select(notebook.get_current_view()->file_path);
@ -158,18 +126,31 @@ Window::Window() : box(Gtk::ORIENTATION_VERTICAL), compiling(false) {
} // Window constructor
void Window::configure() {
Singleton::Config::main()->read();
auto style_context = Gtk::StyleContext::create();
auto screen = Gdk::Screen::get_default();
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()
style_context->add_provider_for_screen(screen, css_provider, GTK_STYLE_PROVIDER_PRIORITY_SETTINGS);
Singleton::menu()->set_keys();
}
void Window::create_menu() {
menu.action_group->add(Gtk::Action::create("FileQuit", "Quit juCi++"), Gtk::AccelKey(menu.key_map["quit"]), [this]() {
void Window::set_menu_actions() {
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();
});
menu.action_group->add(Gtk::Action::create("FileNewFile", "New File"), Gtk::AccelKey(menu.key_map["new_file"]), [this]() {
menu->add_action("new_file", [this]() {
boost::filesystem::path path = Dialog::new_file();
if(path!="") {
if(boost::filesystem::exists(path)) {
@ -187,7 +168,7 @@ void Window::create_menu() {
}
}
});
menu.action_group->add(Gtk::Action::create("FileNewFolder", "New Folder"), Gtk::AccelKey(menu.key_map["new_folder"]), [this]() {
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)) {
@ -198,14 +179,12 @@ void Window::create_menu() {
}
else
Singleton::terminal()->print("Error: "+path.string()+" already exists.\n");
}
Singleton::directories()->select(path);
}
});
menu.action_group->add(Gtk::Action::create("FileNewProject", "New Project"));
menu.action_group->add(Gtk::Action::create("FileNewProjectCpp", "C++"), [this]() {
menu->add_action("new_project_cpp", [this]() {
boost::filesystem::path project_path = Dialog::new_folder();
if(project_path=="")
return;
if(project_path!="") {
auto project_name=project_path.filename().string();
for(size_t c=0;c<project_name.size();c++) {
if(project_name[c]==' ')
@ -232,16 +211,37 @@ void Window::create_menu() {
}
else
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();
if (path!="" && boost::filesystem::exists(path))
Singleton::directories()->open(path);
});
menu.action_group->add(Gtk::Action::create("FileSaveAs", "Save As"), Gtk::AccelKey(menu.key_map["save_as"]), [this]() {
menu->add_action("save", [this]() {
if(notebook.get_current_page()!=-1) {
if(notebook.save_current()) {
if(notebook.get_current_page()!=-1) {
if(notebook.get_current_view()->file_path==Singleton::Config::main()->juci_home_path()/"config"/"config.json") {
configure();
for(int c=0;c<notebook.size();c++) {
notebook.get_view(c)->configure();
notebook.configure(c);
}
}
}
}
}
});
menu->add_action("save_as", [this]() {
if(notebook.get_current_page()!=-1) {
auto path = Dialog::save_file();
if(path!="") {
std::ofstream file(path);
@ -256,92 +256,79 @@ void Window::create_menu() {
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.action_group->add(Gtk::Action::create("FileSave", "Save"), Gtk::AccelKey(menu.key_map["save"]), [this]() {
if(notebook.save_current()) {
menu->add_action("edit_undo", [this]() {
if(notebook.get_current_page()!=-1) {
if(notebook.get_current_view()->file_path==Singleton::Config::main()->juci_home_path()/"config"/"config.json") {
configure();
for(int c=0;c<notebook.size();c++) {
notebook.get_view(c)->configure();
notebook.configure(c);
auto undo_manager = notebook.get_current_view()->get_source_buffer()->get_undo_manager();
if (undo_manager->can_undo()) {
undo_manager->undo();
notebook.get_current_view()->scroll_to(notebook.get_current_view()->get_buffer()->get_insert());
}
}
});
menu->add_action("edit_redo", [this]() {
if(notebook.get_current_page()!=-1) {
auto undo_manager = notebook.get_current_view()->get_source_buffer()->get_undo_manager();
if(undo_manager->can_redo()) {
undo_manager->redo();
notebook.get_current_view()->scroll_to(notebook.get_current_view()->get_buffer()->get_insert());
}
}
});
menu.action_group->add(Gtk::Action::create("EditCopy", "Copy"), Gtk::AccelKey(menu.key_map["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.action_group->add(Gtk::Action::create("EditCut", "Cut"), Gtk::AccelKey(menu.key_map["edit_cut"]), [this]() {
menu->add_action("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]() {
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.action_group->add(Gtk::Action::create("EditFind", "Find"), Gtk::AccelKey(menu.key_map["edit_find"]), [this]() {
menu->add_action("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) {
auto undo_manager = notebook.get_current_view()->get_source_buffer()->get_undo_manager();
if (undo_manager->can_undo()) {
undo_manager->undo();
notebook.get_current_view()->scroll_to(notebook.get_current_view()->get_buffer()->get_insert());
}
}
});
menu.action_group->add(Gtk::Action::create("EditRedo", "Redo"), Gtk::AccelKey(menu.key_map["edit_redo"]), [this]() {
if(notebook.get_current_page()!=-1) {
auto undo_manager = notebook.get_current_view()->get_source_buffer()->get_undo_manager();
if(undo_manager->can_redo()) {
undo_manager->redo();
notebook.get_current_view()->scroll_to(notebook.get_current_view()->get_buffer()->get_insert());
}
}
});
menu.action_group->add(Gtk::Action::create("SourceSpellCheck", "Spell Check"));
menu.action_group->add(Gtk::Action::create("SourceSpellCheckBuffer", "Spell Check Buffer"), Gtk::AccelKey(menu.key_map["source_spellcheck"]), [this]() {
menu->add_action("source_spellcheck", [this]() {
if(notebook.get_current_page()!=-1)
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)
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)
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();
});
menu.action_group->add(Gtk::Action::create("SourceIndentationAutoIndentBuffer", "Auto-Indent Current Buffer"), Gtk::AccelKey(menu.key_map["source_indentation_auto_indent_buffer"]), [this]() {
Singleton::terminal()->print("Auto-Indent Current Buffer will soon be implemented.\n");
menu->add_action("source_indentation_auto_indent_buffer", [this]() {
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();
});
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) {
while(gtk_events_pending())
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);
}
});
menu.action_group->add(Gtk::Action::create("SourceGotoDeclaration", "Go to Declaration"), Gtk::AccelKey(menu.key_map["source_goto_declaration"]), [this]() {
if(notebook.get_current_page()!=-1) {
if(notebook.get_current_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]() {
menu->add_action("source_find_documentation", [this]() {
if(notebook.get_current_page()!=-1) {
if(notebook.get_current_view()->get_token_data) {
auto data=notebook.get_current_view()->get_token_data();
@ -414,14 +377,53 @@ 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_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_view()->apply_fix_its) {
notebook.get_current_view()->apply_fix_its();
@ -429,7 +431,7 @@ void Window::create_menu() {
}
});
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)
return;
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)
return;
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.labels.emplace_back();
auto label_it=entry_box.labels.begin();
@ -516,29 +519,20 @@ void Window::create_menu() {
});
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();
});
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);
});
menu.action_group->add(Gtk::Action::create("WindowCloseTab", "Close Tab"), Gtk::AccelKey(menu.key_map["close_tab"]), [this]() {
notebook.close_current_page();
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]() {
menu->add_action("next_tab", [this]() {
if(notebook.get_current_page()!=-1) {
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) {
int previous_page=notebook.get_current_page()-1;
if(previous_page<0)
@ -546,10 +540,31 @@ void Window::create_menu() {
notebook.open(notebook.get_view(previous_page)->file_path);
}
});
menu.action_group->add(Gtk::Action::create("HelpAbout", "About"), [this] () {
about.show();
about.present();
menu->add_action("close_tab", [this]() {
notebook.close_current_page();
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) {

10
src/window.h

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

Loading…
Cancel
Save