diff --git a/.gitmodules b/.gitmodules index 7e45ba14..741df68b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -5,3 +5,7 @@ [submodule "libclangmm"] path = libclangmm url = https://github.com/cppit/libclangmm.git +[submodule "pybind11"] + path = pybind11 + url = https://github.com/wjakob/pybind11.git + branch = stable \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 57e2f81d..11bfe38f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,11 +1,8 @@ cmake_minimum_required (VERSION 2.8.4) -set(project_name juci) -#set(module juci_to_python_api) +set(application_name "juci") -#set(lib_install_path "/usr/local/lib/python2.7/dist-packages/") - -project (${project_name}) +project (${application_name}) add_subdirectory("src") diff --git a/docs/install.md b/docs/install.md index 2dea6af8..9f92b71b 100644 --- a/docs/install.md +++ b/docs/install.md @@ -33,7 +33,6 @@ Install dependencies: ```sh sudo apt-get install git cmake make g++ libclang-3.5-dev liblldb-3.5-dev clang-format-3.5 pkg-config libboost-system-dev libboost-thread-dev libboost-filesystem-dev libboost-log-dev libboost-regex-dev libgtksourceviewmm-3.0-dev aspell-en libaspell-dev ``` - Get juCi++ source, compile and install: ```sh git clone --recursive https://github.com/cppit/jucipp diff --git a/plugins/snippet.py b/plugins/snippet.py deleted file mode 100644 index 5f77be68..00000000 --- a/plugins/snippet.py +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/python -#snippet plugin -import juci_to_python_api as juci, inspect - -def initPlugin(): - juci.addMenuElement("Snippet") - juci.addSubMenuElement("SnippetMenu", #name of parent menu - "Insert snippet", #menu description - "insertSnippet()", #function to execute - inspect.getfile(inspect.currentframe()), #plugin path - "space") -snippets = {} - -snippets["for"] = """\ -for(int i=0; i - -int main(int argc, char *argv[]) { - std::cout << "Hello, world! << std::endl; -} -""" - -def getSnippet(word): - try: - output = snippets[word] - except KeyError: - output = word - return output - -def insertSnippet(): - theWord=juci.getWord() - output=getSnippet(theWord) - juci.replaceWord(output) - - diff --git a/pybind11 b/pybind11 new file mode 160000 index 00000000..d2385e8f --- /dev/null +++ b/pybind11 @@ -0,0 +1 @@ +Subproject commit d2385e8fc6a3008cab96532c99db4c3d57541fc5 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 52ed79ec..a1848988 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -25,9 +25,14 @@ if(MSYS) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMSYS_PROCESS_USE_SH") endif() -INCLUDE(FindPkgConfig) - find_package(LibClang REQUIRED) +find_package(Boost 1.54 COMPONENTS thread log regex system filesystem REQUIRED) +find_package(ASPELL REQUIRED) +find_package(PythonLibs 3 REQUIRED) +set(PYBIND11_INCLUDE_DIR ../pybind11/include) +set(LIBCLANGMM_INCLUDE_DIR ../libclangmm/src) +set(TINY_PROCESS_INCLUDE_DIR ../tiny-process-library) + string(REPLACE libclang liblldb LIBLLDB_LIBRARIES "${LIBCLANG_LIBRARIES}") if(EXISTS "${LIBLLDB_LIBRARIES}") set(LIBLLDB_FOUND TRUE) @@ -41,55 +46,80 @@ else() set(LIBLLDB_LIBRARIES "") message("liblldb not found. Building juCi++ without debugging support") endif() -#find_package(PythonLibs 2.7) - -#find_package(Boost 1.55 COMPONENTS python thread log system filesystem REQUIRED) -find_package(Boost 1.54 COMPONENTS thread log system filesystem regex REQUIRED) - -pkg_check_modules(GTKMM gtkmm-3.0 REQUIRED) # The name GTKMM is set here for the variables abouve +include(FindPkgConfig) +pkg_check_modules(GTKMM gtkmm-3.0 REQUIRED) pkg_check_modules(GTKSVMM gtksourceviewmm-3.0 REQUIRED) +pkg_check_modules(PYGOBJECT pygobject-3.0 REQUIRED) + + +set(global_includes + ${Boost_INCLUDE_DIRS} + ${GTKMM_INCLUDE_DIRS} + ${GTKSVMM_INCLUDE_DIRS} + ${LIBCLANG_INCLUDE_DIRS} + ${LIBCLANGMM_INCLUDE_DIR} + ${ASPELL_INCLUDE_DIR} + ${PYTHON_INCLUDE_DIRS} + ${PYBIND11_INCLUDE_DIR} + ${TINY_PROCESS_INCLUDE_DIR} + ${PYGOBJECT_INCLUDE_DIRS} +) -find_package(ASPELL REQUIRED) +set(global_libraries + ${LIBCLANG_LIBRARIES} + ${GTKMM_LIBRARIES} + ${GTKSVMM_LIBRARIES} + ${Boost_LIBRARIES} + ${ASPELL_LIBRARIES} + ${PYTHON_LIBRARIES} + ${LIBLLDB_LIBRARIES} +) -set(source_files juci.h - juci.cc - menu.h - menu.cc - source.h - source.cc - source_clang.h - source_clang.cc - selectiondialog.h - selectiondialog.cc - config.h +set(application_files + cmake.cc + cmake.h config.cc - filesystem.h - filesystem.cc - window.cc - window.h + config.h + dialogs.cc dialogs.h -# api.h -# api.cc + directories.cc + directories.h + dispatcher.cc + dispatcher.h + entrybox.cc + entrybox.h + files.h + filesystem.cc + filesystem.h + juci.cc + juci.h + logging.h + main.cc + menu.cc + menu.h notebook.cc notebook.h - entrybox.h - entrybox.cc - directories.h - directories.cc - terminal.h - terminal.cc - tooltips.h - tooltips.cc - cmake.h - cmake.cc - dialogs.cc - project.h project.cc + project.h project_build.h project_build.cc - dispatcher.h - dispatcher.cc + python_api.cc + python_api.h + python_interpreter.cc + python_interpreter.h + selectiondialog.cc + selectiondialog.h + source.cc + source.h + source_clang.cc + source_clang.h + terminal.cc + terminal.h + tooltips.cc + tooltips.h + window.cc + window.h ../libclangmm/src/CodeCompleteResults.cc ../libclangmm/src/CompilationDatabase.cc @@ -97,73 +127,32 @@ set(source_files juci.h ../libclangmm/src/CompileCommands.cc ../libclangmm/src/CompletionString.cc ../libclangmm/src/Cursor.cc + ../libclangmm/src/Diagnostic.cc + ../libclangmm/src/Diagnostic.cc ../libclangmm/src/Index.cc ../libclangmm/src/SourceLocation.cc ../libclangmm/src/SourceRange.cc ../libclangmm/src/Token.cc ../libclangmm/src/Tokens.cc - ../libclangmm/src/TranslationUnit.cc - ../libclangmm/src/Diagnostic.cc + ../libclangmm/src/TranslationUnit.cc ../libclangmm/src/Utility.cc ../tiny-process-library/process.cpp) if(LIBLLDB_FOUND) - list(APPEND source_files debug_clang.h debug_clang.cc) + list(APPEND application_files debug_clang.h debug_clang.cc) endif() if(MSYS) - list(APPEND source_files dialogs_unix.cc) #dialogs_win.cc does not work any more because of missing SHCreateItemFromParsingName - list(APPEND source_files ../tiny-process-library/process_win.cpp) + list(APPEND application_files dialogs_unix.cc ../tiny-process-library/process_win.cpp) else() - list(APPEND source_files dialogs_unix.cc) - list(APPEND source_files ../tiny-process-library/process_unix.cpp) + list(APPEND application_files dialogs_unix.cc ../tiny-process-library/process_unix.cpp) endif() -add_executable(${project_name} ${source_files}) - -# add_library(${module} SHARED -# api -# api_ext) - -include_directories( - ${Boost_INCLUDE_DIRS} -# ${PYTHON_INCLUDE_DIRS} - ${GTKMM_INCLUDE_DIRS} - ${GTKSVMM_INCLUDE_DIRS} - ${LIBCLANG_INCLUDE_DIRS} - ${ASPELL_INCLUDE_DIR} - ../libclangmm/src - ../tiny-process-library -) - -link_directories( - ${GTKMM_LIBRARY_DIRS} - ${GTKSVMM_LIBRARY_DIRS} - ${Boost_LIBRARY_DIRS} -# ${PYTHON_INCLUDE_DIRS} - ${LIBCLANG_LIBRARY_DIRS} -) - -# set_target_properties(${module} -# PROPERTIES PREFIX "" -# LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/lib/") - -# target_link_libraries(${module} ${PYTHON_LIBRARIES} ${Boost_LIBRARIES}) -# target_link_libraries(${module} ${Boost_LIBRARIES}) - -target_link_libraries(${project_name} - ${LIBCLANG_LIBRARIES} - ${GTKMM_LIBRARIES} - ${GTKSVMM_LIBRARIES} - ${Boost_LIBRARIES} - ${ASPELL_LIBRARIES} - ${LIBLLDB_LIBRARIES} - #${PYTHON_LIBRARIES} -) +include_directories(${global_includes}) +add_executable(${application_name} ${application_files}) +target_link_libraries(${application_name} ${global_libraries}) -# install(TARGETS ${project_name} ${module} -install(TARGETS ${project_name} +install(TARGETS ${application_name} RUNTIME DESTINATION bin -# LIBRARY DESTINATION ${lib_install_path} ) diff --git a/src/api.cc b/src/api.cc deleted file mode 100644 index be1381db..00000000 --- a/src/api.cc +++ /dev/null @@ -1,213 +0,0 @@ -#include "api.h" -#include "logging.h" -#include "singletons.h" - -Menu* PluginApi::menu=nullptr; -Notebook* PluginApi::notebook=nullptr; -///////////////////////////// -//// API ServiceProvider //// -///////////////////////////// -PluginApi::PluginApi(Notebook* notebook, Menu* menu) { - DEBUG("Adding pointers for the API"); - this->notebook = notebook; - this->menu = menu; - DEBUG("Initiating plugins(from plugins.py).."); -#ifndef __APPLE__ - //InitPlugins(); //TODO: fix this -#endif - DEBUG("Plugins initiated.."); -} - -void PluginApi::ReplaceWord(std::string word) { - Glib::RefPtr buffer = libjuci::BufferFromNotebook(); - Gtk::TextIter word_start = libjuci::IterFromNotebook(); - Gtk::TextIter word_end = libjuci::IterFromNotebook(); - libjuci::IterToWordStart(word_start); - libjuci::IterToWordEnd(word_end); - if (word_start != word_end) { - buffer->erase(word_start, word_end); - Gtk::TextIter current = libjuci::IterFromNotebook(); - buffer->insert(current, word); - } -} - -void PluginApi::ReplaceLine(std::string line) { - WARNING("use of unimplemented method"); -} - -std::string PluginApi::GetWord() { - Glib::RefPtr buffer = libjuci::BufferFromNotebook(); - Gtk::TextIter word_start = libjuci::IterFromNotebook(); - Gtk::TextIter word_end = libjuci::IterFromNotebook(); - - libjuci::IterToWordStart(word_start); - libjuci::IterToWordEnd(word_end); - - if (word_start < word_end) { - std::string word = buffer->get_text(word_start, word_end); - return word; - } - return ""; -} - -void PluginApi::InitPlugins() { - libjuci::LoadPlugin(Singleton::config_dir() + "plugins.py"); -} - -void PluginApi::AddMenuElement(std::string plugin_name) { - DEBUG("Adding menu element for "+plugin_name); - AddMenuXml(plugin_name, "PluginMenu"); - std::string plugin_action_name = plugin_name+"Menu"; - menu->action_group->add(Gtk::Action::create(plugin_action_name, plugin_name)); -} - -void PluginApi::AddSubMenuElement(std::string parent_menu, - std::string menu_name, - std::string menu_func_name, - std::string plugin_path, - std::string menu_keybinding) { - AddSubMenuXml(menu_func_name, parent_menu); - menu->action_group->add(Gtk::Action::create(menu_func_name, - menu_name), - Gtk::AccelKey(menu_keybinding), - [=]() { - libjuci::LoadPluginFunction(menu_func_name, plugin_path); - }); -} - -void PluginApi::AddMenuXml(std::string plugin_name, std::string parent_menu) { - std::string temp_menu = menu->ui; - std::size_t plugin_menu_pos = temp_menu.find(parent_menu); - // +2 gets you outside of the tag:<'menu_name'> - plugin_menu_pos+=parent_menu.size() +2; - std::string menu_prefix = temp_menu.substr(0, plugin_menu_pos); - std::string menu_suffix = temp_menu.substr(plugin_menu_pos); - std::string menu_input = - " " - " "; - - menu->ui = menu_prefix + menu_input + menu_suffix; -} - -void PluginApi::AddSubMenuXml(std::string plugin_name, - std::string parent_menu) { - std::string temp_menu = menu->ui; - - std::size_t parent_menu_pos = temp_menu.find(parent_menu); - // +2 gets you outside of the tag:<'menu_name'> - parent_menu_pos+=parent_menu.size() +2; - std::string menu_prefix = temp_menu.substr(0, parent_menu_pos); - std::string menu_suffix = temp_menu.substr(parent_menu_pos); - - std::string menu_input =""; - menu->ui = menu_prefix + menu_input + menu_suffix; -} - -/////////////////////// -//// Api to python //// -/////////////////////// -void libjuci::ReplaceWord(const std::string word) { - PluginApi::ReplaceWord(word); -} - -void libjuci::ReplaceLine(const std::string line) { - std::cout << "unimplemented: " << __func__ << " called" - << std::endl; -} -std::string libjuci::GetWord() { - return PluginApi::GetWord(); -} - -void libjuci::AddMenuElement(std::string plugin_name) { - PluginApi::AddMenuElement(plugin_name); -} - -void libjuci::AddSubMenuElement(std::string parent_menu, - std::string menu_name, - std::string menu_func_name, - std::string plugin_path, - std::string menu_keybinding) { - PluginApi::AddSubMenuElement(parent_menu, - menu_name, - menu_func_name, - plugin_path, - menu_keybinding); -} - -////////////////////////////// -//// Boost.Python methods //// -////////////////////////////// -namespace bp = boost::python; - -bp::api::object libjuci::OpenPythonScript(const std::string path, - bp::api::object python_name_space) { - bp::str str_path(path); - return bp::exec_file(str_path, python_name_space); -} - -void libjuci::LoadPlugin(const std::string& plugin_name) { - try { - Py_Initialize(); - bp::api::object main_module = bp::import("__main__"); - bp::api::object main_namespace = - main_module.attr("__dict__"); - bp::api::object ignored2 = - OpenPythonScript(plugin_name, main_namespace); - }catch (bp::error_already_set const&) { - PyErr_Print(); - } -} - -void libjuci::LoadPluginFunction(const std::string &function_name, - const std::string &plugin_path) { - try { - Py_Initialize(); - bp::api::object main_module = bp::import("__main__"); - bp::api::object main_namespace = main_module.attr("__dict__"); - bp::api::object ignored2 = OpenPythonScript(plugin_path, main_namespace); - bp::str func_name(function_name); - bp::api::object returnValue = bp::eval(func_name, main_namespace); - }catch (bp::error_already_set const&) { - PyErr_Print(); - } -} - -void libjuci::InitPlugin(const std::string& plugin_path) { - try { - Py_Initialize(); - bp::api::object main_module = bp::import("__main__"); - bp::api::object main_namespace = main_module.attr("__dict__"); - bp::api::object ignored2 = OpenPythonScript(plugin_path, main_namespace); - bp::object returnValue = bp::eval("initPlugin()", main_namespace); - // do something with return_value - }catch (bp::error_already_set const&) { - PyErr_Print(); - } -} - -/////////////////////// -//// Glib wrappers //// -/////////////////////// -void libjuci::IterToWordStart(Gtk::TextIter &iter) { - if (!iter.starts_line()) { - while (!iter.starts_word()) { - iter.backward_char(); - } - } -} - -void libjuci::IterToWordEnd(Gtk::TextIter &iter) { - if (!iter.ends_line()) { - while (!iter.ends_word()) { - iter.forward_char(); - } - } -} - -Glib::RefPtr libjuci::BufferFromNotebook() { - return Glib::RefPtr(PluginApi::notebook->get_current_view()->get_buffer()); -} - -Gtk::TextIter libjuci::IterFromNotebook() { - return libjuci::BufferFromNotebook()->get_insert()->get_iter(); -} diff --git a/src/api.h b/src/api.h deleted file mode 100644 index a3aafcaf..00000000 --- a/src/api.h +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef JUCI_API_H_ -#define JUCI_API_H_ - -#include -#include -#include -#include "notebook.h" -#include "menu.h" - -//////////////////// -//// Plugin Api //// -//////////////////// -class PluginApi { -public: - PluginApi(Notebook* notebook, Menu* menu); - static Menu* menu; - static Notebook* notebook; - static void InitPlugins(); - // for Python module: - static std::string GetWord(); - // menu management - static void AddMenuElement(const std::string plugin_name); - static void AddSubMenuElement(const std::string parent_menu, - const std::string menu_name, - const std::string menu_func_name, - const std::string plugin_path, - const std::string menu_keybinding); - static void ReplaceWord(const std::string word); - static void ReplaceLine(const std::string line); -protected: - static void AddMenuXml(std::string plugin_name, std::string parent_menu); - static void AddSubMenuXml(std::string plugin_name, std::string parent_menu); -}; // PluginApi -namespace libjuci { - /////////////////////// - //// Glib wrappers //// - /////////////////////// - void IterToWordStart(Gtk::TextIter &iter); - void IterToWordEnd(Gtk::TextIter &iter); - Gtk::TextIter IterFromNotebook(); - Glib::RefPtr BufferFromNotebook(); - /////////////////////// - //// Api to python //// - /////////////////////// - void ReplaceWord(const std::string word); - void ReplaceLine(const std::string line); - std::string GetWord(); - - void AddMenuElement(const std::string plugin_name); - - void AddSubMenuElement(const std::string parent_menu, - const std::string menu_name, - const std::string menu_func_name, - const std::string plugin_path, - const std::string menu_keybinding); - void AddMenuXml(const std::string plugin_name, - const std::string parent_menu); - void AddSubMenuXml(const std::string plugin_name, - const std::string parent_menu); - ////////////////////////////// - //// Boost.Python methods //// - ////////////////////////////// - namespace bp = boost::python; - bp::api::object OpenPythonScript(const std::string path, - bp::api::object python_name_space); - void LoadPlugin(const std::string& plugin_name); - void LoadPluginFunction(const std::string &function_name, - const std::string &plugin_path); - - void InitPlugin(const std::string& plugin_path); -} // namespace libjuci -#endif // JUCI_API_H_ diff --git a/src/api_ext.cc b/src/api_ext.cc deleted file mode 100644 index 9b8b1ba2..00000000 --- a/src/api_ext.cc +++ /dev/null @@ -1,15 +0,0 @@ -#include "api.h" - -BOOST_PYTHON_MODULE(juci_to_python_api) { - using namespace boost::python; - // plugin inclusion - def("addMenuElement", &libjuci::AddMenuElement); - def("addSubMenuElement", &libjuci::AddSubMenuElement); - def("loadPlugin", &libjuci::LoadPlugin); - def("initPlugin", &libjuci::InitPlugin); - - // text editing - def("replaceLine", &libjuci::ReplaceLine); - def("replaceWord", &libjuci::ReplaceWord); - def("getWord", &libjuci::GetWord); - } // module::juci_to_python_api diff --git a/src/config.cc b/src/config.cc index aa5c7c18..74e46aa8 100644 --- a/src/config.cc +++ b/src/config.cc @@ -60,17 +60,23 @@ void Config::load() { void Config::find_or_create_config_files() { auto config_dir = home/"config"; auto config_json = config_dir/"config.json"; - auto plugins_py = config_dir/"plugins.py"; - - boost::filesystem::create_directories(config_dir); // io exp captured by calling method + auto plugin_dir = home/"plugins"; + + auto tools_path = plugin_dir/"tools.py"; + auto snippet_path = plugin_dir/"snippet.py"; + + boost::filesystem::create_directories(config_dir); + boost::filesystem::create_directories(plugin_dir); if (!boost::filesystem::exists(config_json)) - filesystem::write(config_json, configjson); // vars configjson and pluginspy - if (!boost::filesystem::exists(plugins_py)) // live in files.h - filesystem::write(plugins_py, pluginspy); - + filesystem::write(config_json, configjson); + if (!boost::filesystem::exists(tools_path)) + filesystem::write(tools_path, tools_py); + if (!boost::filesystem::exists(snippet_path)) + filesystem::write(snippet_path, snippet_py); + auto juci_style_path = home/"styles"; - boost::filesystem::create_directories(juci_style_path); // io exp captured by calling method + boost::filesystem::create_directories(juci_style_path); juci_style_path/="juci-light.xml"; if(!boost::filesystem::exists(juci_style_path)) @@ -103,6 +109,9 @@ void Config::retrieve_config() { project.make_command=cfg.get("project.make_command"); project.cmake_command=cfg.get("project.cmake_command"); + python.site_packages=cfg.get("python.site_packages", "/usr/lib/python3.5/site-packages"); + python.plugin_directory=cfg.get("python.plugin_directory", (home/"plugins").string()); + terminal.history_size=cfg.get("terminal_history_size"); terminal.clang_format_command="clang-format"; #ifdef __linux diff --git a/src/config.h b/src/config.h index 1add0422..75f314c3 100644 --- a/src/config.h +++ b/src/config.h @@ -41,6 +41,12 @@ class Config { bool save_on_compile_or_run; }; + class Python { + public: + std::string site_packages; + std::string plugin_directory; + }; + class Source { public: class DocumentationSearch { @@ -84,7 +90,8 @@ class Config { Terminal terminal; Project project; Source source; - + Python python; + const boost::filesystem::path& juci_home_path() const { return home; } private: diff --git a/src/files.h b/src/files.h index c69c48dc..5ec144f8 100644 --- a/src/files.h +++ b/src/files.h @@ -320,82 +320,204 @@ const std::string juci_dark_blue_style = "\n" "\n"; -const std::string pluginspy = -"#!/usr/bin/python \n" -"import juci_to_python_api as juci \n" -"import glob \n" -"\n" -"def loadplugins(): \n" -" plugin_files = glob.glob(\"../plugins/*.py\") \n" -" for current_file in plugin_files: \n" -" juci.initPlugin(current_file) \n" -"loadplugins() \n"; +const std::string snippet_py = +"import libjuci, os, gi\n" +"gi.require_version('Gtk', '3.0')\n" +"\n" +"from gi.repository import Gtk, Gio\n" +"from libjuci import beta, editor, terminal\n" +"from os import path\n" +"\n" +"def add_menu(position, label, items) :\n" +" plugin_menu = beta.get_menu_from_name('plugin_menu')\n" +" if not plugin_menu :\n" +" libjuci.terminal.println('plugin_menu menu does not exist')\n" +" return\n" +" sub_menu = Gio.Menu.new()\n" +" i = 0\n" +" app = beta.get_gtk_application()\n" +" for item in items :\n" +" sub_menu.insert(i, item['label'], 'app.'+item['action'])\n" +" i = i + 1\n" +" python_action = Gio.SimpleAction.new(item['action'], None)\n" +" python_action.connect('activate', item['method'])\n" +" app.add_action(python_action)\n" +" app.add_accelerator(item['accel'], 'app.'+item['action'], None)\n" +" \n" +" if plugin_menu.get_n_items() >= position :\n" +" plugin_menu.remove(position)\n" +" \n" +" plugin_menu.insert_submenu(position, label, sub_menu)\n" +" \n" +"def init() :\n" +" items = [\n" +" {\n" +" 'label': 'Insert snippet',\n" +" 'action': 'insert_snippet',\n" +" 'accel': 'space',\n" +" 'method': insert_snippet\n" +" }\n" +" ]\n" +" add_menu(1, '_Snippet', items) \n" +" \n" +"def get_ifndef() :\n" +" file_name = editor.get_file_name()\n" +" package, file_name = path.split(file_name)\n" +" file_name, file_ext = path.splitext(file_name)\n" +" package = path.basename(package)\n" +" guard = package + '_' + file_name + '_' + file_ext[1:len(file_ext)] + '_\\n'\n" +" res = '#ifndef ' + guard\n" +" res += '#define ' + guard\n" +" res += '#endif // ' + guard\n" +" return res\n" +"\n" +"def get_snippet(word) :\n" +" snippets = {}\n" +"\n" +" snippets['for'] = '''\\\n" +"for (int i = 0; i < v.size(); i++) {\n" +" // std::cout << v[i] << std::endl;\n" +" // Write code here\n" +"}\\n" +"'''\n" +" snippets['if'] = '''\\\n" +"if(){\n" +" // Write code here\n" +"}\\n" +"'''\n" +"\n" +" snippets['cout'] = '''\\\n" +"cout << \\n" +"'''\n" +" \n" +" snippets['io'] = '''\\\n" +"#include \n" +"using namespace std;\n" +"'''\n" +" snippets['ifndef'] = get_ifndef()\n" +" \n" +" try :\n" +" output = snippets[word]\n" +" except KeyError :\n" +" output = word\n" +" return output\n" +" \n" +"def get_iter_at_cursor(gtk_text_buffer) :\n" +" mark = gtk_text_buffer.get_insert()\n" +" return gtk_text_buffer.get_iter_at_mark(mark)\n" +"\n" +"def get_current_line_text(gtk_text_buffer) :\n" +" line_number = get_iter_at_cursor(gtk_text_buffer).get_line()\n" +" start_iter = gtk_text_buffer.get_iter_at_line(line_number)\n" +" end_iter = gtk_text_buffer.get_iter_at_line(line_number+1)\n" +" end_iter.backward_char()\n" +" return gtk_text_buffer.get_text(start_iter, end_iter, 0)\n" +"\n" +"def add_indention(text_line, output) :\n" +" tab_info = editor.get_tab_char_and_size();\n" +" indent = 0\n" +" for c in text_line :\n" +" if c is not tab_info[0]:\n" +" break\n" +" indent = indent + 1\n" +" if indent <= 0 :\n" +" return output\n" +" text_indent = ''\n" +" for x in range(0, indent) :\n" +" text_indent = text_indent + tab_info[0]\n" +" text_lines = output.split('\\n')\n" +" res = ''\n" +" for text_line in text_lines :\n" +" res += text_indent + text_line + '\\n'\n" +" return res[indent:len(res)]\n" +"\n" +"def insert_snippet(action, param) :\n" +" gtk_text_buffer = editor.get_current_gtk_text_buffer()\n" +" if not gtk_text_buffer :\n" +" return\n" +" input_line = get_current_line_text(gtk_text_buffer)\n" +" if not input_line or input_line is '' :\n" +" return\n" +" line_offset = get_iter_at_cursor(gtk_text_buffer).get_line_index()\n" +" first_backwards_space = input_line.rfind(' ', 0, line_offset)\n" +" first_backwards_space = first_backwards_space + 1\n" +" snippet_key_word = input_line[first_backwards_space:line_offset]\n" +" snippet = get_snippet(snippet_key_word)\n" +" if snippet == snippet_key_word :\n" +" return\n" +" snippet = add_indention(input_line, snippet)\n" +" line_number = get_iter_at_cursor(gtk_text_buffer).get_line()\n" +" begin_iter = gtk_text_buffer.get_iter_at_line_offset(line_number,first_backwards_space)\n" +" end_iter = gtk_text_buffer.get_iter_at_line_offset(line_number,line_offset)\n" +" gtk_text_buffer.delete(begin_iter, end_iter)\n" +" gtk_text_buffer.insert_at_cursor(snippet, len(snippet))\n" +" \n" +"init()\n"; -const std::string snippetpy = -"#!/usr/bin/python \n" -"#snippet plugin \n" -"import juci_to_python_api as juci, inspect \n" -" \n" -"def initPlugin(): \n" -" juci.addMenuElement(\"Snippet\") \n" -" juci.addSubMenuElement(\"SnippetMenu\", #name of parent menu \n" -" \"Insert snippet\", #menu description \n" -" \"insertSnippet()\", #function to execute \n" -" inspect.getfile(inspect.currentframe()), #plugin path \n" -" \"space\") \n" -"snippets = {} \n" -" \n" -"snippets[\"for\"] = \"\"\"\\\n" -"for(int i=0; i \n" -" \n" -"int main(int argc, char *argv[]) { \n" -" std::cout << \"Hello, world! << std::endl; \n" -"} \n" -"\"\"\" \n" -" \n" -"def getSnippet(word): \n" -" try: \n" -" output = snippets[word] \n" -" except KeyError: \n" -" output = word \n" -" return output \n" +const std::string tools_py = +"import libjuci, gi, os\n" +"gi.require_version('Gtk', '3.0')\n" +"from gi.repository import Gtk, Gio\n" +"\n" +"from libjuci import beta\n" +"\n" +"favorite = os.environ['HOME']\n" +"plugin = os.environ['HOME']\n" +"favorite_file = os.environ['HOME']\n" +"\n" +"def add_menu(position, label, items) :\n" +" plugin_menu = beta.get_menu_from_name('plugin_menu')\n" +" if not plugin_menu :\n" +" libjuci.terminal.println('plugin_menu menu does not exist')\n" +" return\n" +" sub_menu = Gio.Menu.new()\n" +" i = 0\n" +" app = beta.get_gtk_application()\n" +" for item in items :\n" +" sub_menu.insert(i, item['label'], 'app.'+item['action'])\n" +" i = i + 1\n" +" python_action = Gio.SimpleAction.new(item['action'], None)\n" +" python_action.connect('activate', item['method'])\n" +" app.add_action(python_action)\n" +" app.add_accelerator(item['accel'], 'app.'+item['action'], None)\n" +" \n" +" if plugin_menu.get_n_items() >= position :\n" +" plugin_menu.remove(position)\n" +" \n" +" plugin_menu.insert_submenu(position, label, sub_menu)\n" +"\n" +"def init() :\n" +" items = [\n" +" {\n" +" 'label': 'Open plugin folder',\n" +" 'action': 'open_plugin_folder',\n" +" 'accel': 'p',\n" +" 'method': open_plugin_folder\n" +" },\n" +" {\n" +" 'label': 'Open favorite folder',\n" +" 'action': 'open_favorite_folder',\n" +" 'accel': 'j',\n" +" 'method': open_favorite_folder\n" +" },\n" +" {\n" +" 'label': 'Open favorite file',\n" +" 'action': 'open_favorite_file',\n" +" 'accel': 'j',\n" +" 'method': open_favorite_file\n" +" }\n" +" ]\n" +" add_menu(0, '_Tools', items)\n" +" \n" +"def open_favorite_folder(action, param) :\n" +" libjuci.directories.open(favorite)\n" +" \n" +"def open_favorite_file(action, param) :\n" +" libjuci.directories.open(favorite_file)\n" " \n" -"def insertSnippet(): \n" -" theWord=juci.getWord() \n" -" output=getSnippet(theWord) \n" -" juci.replaceWord(output) \n"; +"def open_plugin_folder(action, param) :\n" +" libjuci.directories.open(plugin)\n" +"\n" +"init()\n"; #endif // JUCI_FILES_H_ diff --git a/src/juci.cc b/src/juci.cc index 5feb99ea..0bc18674 100644 --- a/src/juci.cc +++ b/src/juci.cc @@ -102,15 +102,15 @@ void Application::on_activate() { void Application::on_startup() { Gtk::Application::on_startup(); - Menu::get().build(); - - if (!Menu::get().juci_menu || !Menu::get().window_menu) { + auto juci_menu=Menu::get().menu_refrences["juci_menu"]; + auto window_menu=Menu::get().menu_refrences["window_menu"]; + if (!juci_menu || !window_menu) { std::cerr << "Menu not found." << std::endl; } else { - set_app_menu(Menu::get().juci_menu); - set_menubar(Menu::get().window_menu); + set_app_menu(juci_menu); + set_menubar(window_menu); } } @@ -119,13 +119,7 @@ Application::Application() : Gtk::Application("no.sout.juci", Gio::APPLICATION_N auto log_dir = Config::get().juci_home_path()/"log"/"juci.log"; boost::log::add_file_log(boost::log::keywords::file_name = log_dir, boost::log::keywords::auto_flush = true); JINFO("Logging initalized"); - - Glib::set_application_name("juCi++"); - + Glib::set_application_name("juCi++"); //Gtk::MessageDialog without buttons caused text to be selected, this prevents that Gtk::Settings::get_default()->property_gtk_label_select_on_focus()=false; } - -int main(int argc, char *argv[]) { - return Application().run(argc, argv); -} diff --git a/src/main.cc b/src/main.cc new file mode 100644 index 00000000..6d2b79b3 --- /dev/null +++ b/src/main.cc @@ -0,0 +1,5 @@ +#include "juci.h" + +int main(int argc, char *argv[]) { + return Application().run(argc, argv); +} \ No newline at end of file diff --git a/src/menu.cc b/src/menu.cc index bc005389..d7855c03 100644 --- a/src/menu.cc +++ b/src/menu.cc @@ -1,13 +1,63 @@ #include "menu.h" +#include "window.h" #include "config.h" #include -#include +#include +#include "terminal.h" +// #include "python_interpreter.h" -//TODO: if Ubuntu ever gets fixed, cleanup the Ubuntu specific code -Menu::Menu() { +boost::property_tree::ptree Menu::generate_submenu(const std::string &label){ + boost::property_tree::ptree ptree; + std::stringstream ss; + std::string element( + ""+label+"" + ); + ss << element; + boost::property_tree::read_xml(ss, ptree); + return ptree; +} + +boost::property_tree::ptree Menu::generate_item(const std::string &label, const std::string &action, const std::string &accel){ + boost::property_tree::ptree ptree; + std::stringstream ss; + std::string item( + ""+label+"" + "app."+action+"" + +accel //For Ubuntu... + ); + ss << item; + boost::property_tree::read_xml(ss, ptree); + return ptree; +} + +Menu::Menu() {} + +void Menu::add_action(const std::string &name, std::function action) { + auto g_application=g_application_get_default(); + auto gio_application=Glib::wrap(g_application, true); + auto application=Glib::RefPtr::cast_static(gio_application); + actions[name]=application->add_action(name, action); +} + +void Menu::set_keys() { + auto g_application=g_application_get_default(); + auto gio_application=Glib::wrap(g_application, true); + auto application=Glib::RefPtr::cast_static(gio_application); + for(auto &key: Config::get().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(){ auto accels=Config::get().menu.keys; for(auto &accel: accels) { -#ifdef JUCI_UBUNTU +#ifdef JUCI_UBUNTU_BUGGED_MENU size_t pos=0; std::string second=accel.second; while((pos=second.find('<', pos))!=std::string::npos) { @@ -24,392 +74,361 @@ Menu::Menu() { else accel.second=""; #else - accel.second=""; -#endif - } - - ui_xml = - "" - " " - "
" - " " - " _About" - " app.about" - +accels["about"]+ //For Ubuntu... - " " - "
" - "
" - " " - " _Preferences" - " app.preferences" - +accels["preferences"]+ //For Ubuntu... - " " - "
" - "
" - " " - " _Quit" - " app.quit" - +accels["quit"]+ //For Ubuntu... - " " - "
" - "
" - "" - " " - " " - " _File" - "
" - " " - " _New _File" - " app.new_file" - +accels["new_file"]+ //For Ubuntu... - " " - " " - " _New _Folder" - " app.new_folder" - +accels["new_folder"]+ //For Ubuntu... - " " - " " - " _New _Project" - " " - " C++" - " app.new_project_cpp" - +accels["new_project_cpp"]+ //For Ubuntu... - " " - " " - "
" - "
" - " " - " _Open _File" - " app.open_file" - +accels["open_file"]+ //For Ubuntu... - " " - " " - " _Open _Folder" - " app.open_folder" - +accels["open_folder"]+ //For Ubuntu... - " " - "
" - "
" - " " - " _Save" - " app.save" - +accels["save"]+ //For Ubuntu... - " " - " " - " _Save _As" - " app.save_as" - +accels["save_as"]+ //For Ubuntu... - " " - "
" - "
" - "" - " " - " _Edit" - "
" - " " - " _Undo" - " app.edit_undo" - +accels["edit_undo"]+ //For Ubuntu... - " " - " " - " _Redo" - " app.edit_redo" - +accels["edit_redo"]+ //For Ubuntu... - " " - "
" - "
" - " " - " _Cut" - " app.edit_cut" - +accels["edit_cut"]+ //For Ubuntu... - " " - " " - " _Copy" - " app.edit_copy" - +accels["edit_copy"]+ //For Ubuntu... - " " - " " - " _Paste" - " app.edit_paste" - +accels["edit_paste"]+ //For Ubuntu... - " " - "
" - "
" - " " - " _Find" - " app.edit_find" - +accels["edit_find"]+ //For Ubuntu... - " " - "
" - "
" - "" - " " - " _Source" - "
" - " " - " _Spell _Check" - " " - " _Spell _Check _Buffer" - " app.source_spellcheck" - +accels["source_spellcheck"]+ //For Ubuntu... - " " - " " - " _Clear _Spelling _Errors" - " app.source_spellcheck_clear" - +accels["source_spellcheck_clear"]+ //For Ubuntu... - " " - " " - " _Go _to _Next _Spelling _Error" - " app.source_spellcheck_next_error" - +accels["source_spellcheck_next_error"]+ //For Ubuntu... - " " - " " - "
" - "
" - " " - " _Indentation" - " " - " _Set _Current _Buffer _Tab" - " app.source_indentation_set_buffer_tab" - +accels["source_indentation_set_buffer_tab"]+ //For Ubuntu... - " " - " " - " _Auto-Indent _Current _Buffer" - " app.source_indentation_auto_indent_buffer" - +accels["source_indentation_auto_indent_buffer"]+ //For Ubuntu... - " " - " " - "
" - "
" - " " - " _Go _to _Line" - " app.source_goto_line" - +accels["source_goto_line"]+ //For Ubuntu... - " " - " " - " _Center _Cursor" - " app.source_center_cursor" - +accels["source_center_cursor"]+ //For Ubuntu... - " " - "
" - "
" - " " - " _Find _Documentation" - " app.source_find_documentation" - +accels["source_find_documentation"]+ //For Ubuntu... - " " - "
" - "
" - " " - " _Go to Declaration" - " app.source_goto_declaration" - +accels["source_goto_declaration"]+ //For Ubuntu... - " " - " " - " _Go to Usage" - " app.source_goto_usage" - +accels["source_goto_usage"]+ //For Ubuntu... - " " - " " - " _Go to Method" - " app.source_goto_method" - +accels["source_goto_method"]+ //For Ubuntu... - " " - " " - " _Rename" - " app.source_rename" - +accels["source_rename"]+ //For Ubuntu... - " " - "
" - "
" - " " - " _Go to Next Diagnostic" - " app.source_goto_next_diagnostic" - +accels["source_goto_next_diagnostic"]+ //For Ubuntu... - " " - " " - " _Apply Fix-Its" - " app.source_apply_fix_its" - +accels["source_apply_fix_its"]+ //For Ubuntu... - " " - "
" - "
" - "" - " " - " _Project" - "
" - " " - " _Set _Run _Arguments" - " app.project_set_run_arguments" - +accels["project_set_run_arguments"]+ //For Ubuntu... - " " - " " - " _Compile _and _Run" - " app.compile_and_run" - +accels["compile_and_run"]+ //For Ubuntu... - " " - " " - " _Compile" - " app.compile" - +accels["compile"]+ //For Ubuntu... - " " - "
" - "
" - " " - " _Run _Command" - " app.run_command" - +accels["run_command"]+ //For Ubuntu... - " " - " " - " _Kill _Last _Process" - " app.kill_last_running" - +accels["kill_last_running"]+ //For Ubuntu... - " " - " " - " _Force _Kill _Last _Process" - " app.force_kill_last_running" - +accels["force_kill_last_running"]+ //For Ubuntu... - " " - "
" - "
" - "" - " " - " _Debug" - "
" - " " - " _Set _Run _Arguments" - " app.debug_set_run_arguments" - +accels["debug_set_run_arguments"]+ //For Ubuntu... - " " - " " - " _Start/_Continue" - " app.debug_start_continue" - +accels["debug_start_continue"]+ //For Ubuntu... - " " - " " - " _Stop" - " app.debug_stop" - +accels["debug_stop"]+ //For Ubuntu... - " " - " " - " _Kill" - " app.debug_kill" - +accels["debug_kill"]+ //For Ubuntu... - " " - "
" - "
" - " " - " _Step _Over" - " app.debug_step_over" - +accels["debug_step_over"]+ //For Ubuntu... - " " - " " - " _Step _Into" - " app.debug_step_into" - +accels["debug_step_into"]+ //For Ubuntu... - " " - " " - " _Step _Out" - " app.debug_step_out" - +accels["debug_step_out"]+ //For Ubuntu... - " " - "
" - "
" - " " - " _Backtrace" - " app.debug_backtrace" - +accels["debug_backtrace"]+ //For Ubuntu... - " " - " " - " _Show _Variables" - " app.debug_show_variables" - +accels["debug_show_variables"]+ //For Ubuntu... - " " - "
" - "
" - " " - " _Run Command" - " app.debug_run_command" - +accels["debug_run_command"]+ //For Ubuntu... - " " - "
" - "
" - " " - " _Toggle _Breakpoint" - " app.debug_toggle_breakpoint" - +accels["debug_toggle_breakpoint"]+ //For Ubuntu... - " " - "
" - "
" - " " - " _Go _to _Stop" - " app.debug_goto_stop" - +accels["debug_goto_stop"]+ //For Ubuntu... - " " - "
" - "
" - "" - " " - " _Window" - "
" - " " - " _Next _Tab" - " app.next_tab" - +accels["next_tab"]+ //For Ubuntu... - " " - " " - " _Previous _Tab" - " app.previous_tab" - +accels["previous_tab"]+ //For Ubuntu... - " " - "
" - "
" - " " - " _Close _Tab" - " app.close_tab" - +accels["close_tab"]+ //For Ubuntu... - " " - "
" - "
" - "
" - "
"; -} - -void Menu::add_action(const std::string &name, std::function action) { - auto g_application=g_application_get_default(); - auto gio_application=Glib::wrap(g_application, true); - auto application=Glib::RefPtr::cast_static(gio_application); - - actions[name]=application->add_action(name, action); -} - -void Menu::set_keys() { - auto g_application=g_application_get_default(); - auto gio_application=Glib::wrap(g_application, true); - auto application=Glib::RefPtr::cast_static(gio_application); - - for(auto &key: Config::get().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... + accel.second=""; #endif } + std::string ui_xml = + "" + "" + " " + "
" + " " + " _About" + " app.about" + +accels["about"]+ //For Ubuntu... + " " + "
" + "
" + " " + " _Preferences" + " app.preferences" + +accels["preferences"]+ //For Ubuntu... + " " + "
" + "
" + " " + " _Quit" + " app.quit" + +accels["quit"]+ //For Ubuntu... + " " + "
" + "
" + "" + " " + " " + " _File" + "
" + " " + " _New _File" + " app.new_file" + +accels["new_file"]+ //For Ubuntu... + " " + " " + " _New _Folder" + " app.new_folder" + +accels["new_folder"]+ //For Ubuntu... + " " + " " + " _New _Project" + " " + " C++" + " app.new_project_cpp" + +accels["new_project_cpp"]+ //For Ubuntu... + " " + " " + "
" + "
" + " " + " _Open _File" + " app.open_file" + +accels["open_file"]+ //For Ubuntu... + " " + " " + " _Open _Folder" + " app.open_folder" + +accels["open_folder"]+ //For Ubuntu... + " " + "
" + "
" + " " + " _Save" + " app.save" + +accels["save"]+ //For Ubuntu... + " " + " " + " _Save _As" + " app.save_as" + +accels["save_as"]+ //For Ubuntu... + " " + "
" + "
" + "" + " " + " _Edit" + "
" + " " + " _Undo" + " app.edit_undo" + +accels["edit_undo"]+ //For Ubuntu... + " " + " " + " _Redo" + " app.edit_redo" + +accels["edit_redo"]+ //For Ubuntu... + " " + "
" + "
" + " " + " _Cut" + " app.edit_cut" + +accels["edit_cut"]+ //For Ubuntu... + " " + " " + " _Copy" + " app.edit_copy" + +accels["edit_copy"]+ //For Ubuntu... + " " + " " + " _Paste" + " app.edit_paste" + +accels["edit_paste"]+ //For Ubuntu... + " " + "
" + "
" + " " + " _Find" + " app.edit_find" + +accels["edit_find"]+ //For Ubuntu... + " " + "
" + "
" + "" + " " + " _Source" + "
" + " " + " _Spell _Check" + " " + " _Spell _Check _Buffer" + " app.source_spellcheck" + +accels["source_spellcheck"]+ //For Ubuntu... + " " + " " + " _Clear _Spelling _Errors" + " app.source_spellcheck_clear" + +accels["source_spellcheck_clear"]+ //For Ubuntu... + " " + " " + " _Go _to _Next _Spelling _Error" + " app.source_spellcheck_next_error" + +accels["source_spellcheck_next_error"]+ //For Ubuntu... + " " + " " + "
" + "
" + " " + " _Indentation" + " " + " _Set _Current _Buffer _Tab" + " app.source_indentation_set_buffer_tab" + +accels["source_indentation_set_buffer_tab"]+ //For Ubuntu... + " " + " " + " _Auto-Indent _Current _Buffer" + " app.source_indentation_auto_indent_buffer" + +accels["source_indentation_auto_indent_buffer"]+ //For Ubuntu... + " " + " " + "
" + "
" + " " + " _Go _to _Line" + " app.source_goto_line" + +accels["source_goto_line"]+ //For Ubuntu... + " " + " " + " _Center _Cursor" + " app.source_center_cursor" + +accels["source_center_cursor"]+ //For Ubuntu... + " " + "
" + "
" + " " + " _Find _Documentation" + " app.source_find_documentation" + +accels["source_find_documentation"]+ //For Ubuntu... + " " + "
" + "
" + " " + " _Go to Declaration" + " app.source_goto_declaration" + +accels["source_goto_declaration"]+ //For Ubuntu... + " " + " " + " _Go to Usage" + " app.source_goto_usage" + +accels["source_goto_usage"]+ //For Ubuntu... + " " + " " + " _Go to Method" + " app.source_goto_method" + +accels["source_goto_method"]+ //For Ubuntu... + " " + " " + " _Rename" + " app.source_rename" + +accels["source_rename"]+ //For Ubuntu... + " " + "
" + "
" + " " + " _Go to Next Diagnostic" + " app.source_goto_next_diagnostic" + +accels["source_goto_next_diagnostic"]+ //For Ubuntu... + " " + " " + " _Apply Fix-Its" + " app.source_apply_fix_its" + +accels["source_apply_fix_its"]+ //For Ubuntu... + " " + "
" + "
" + "" + " " + " _Project" + "
" + " " + " _Compile _and _Run" + " app.compile_and_run" + +accels["compile_and_run"]+ //For Ubuntu... + " " + " " + " _Compile" + " app.compile" + +accels["compile"]+ //For Ubuntu... + " " + "
" + "
" + " " + " _Run _Command" + " app.run_command" + +accels["run_command"]+ //For Ubuntu... + " " + " " + " _Kill _Last _Process" + " app.kill_last_running" + +accels["kill_last_running"]+ //For Ubuntu... + " " + " " + " _Force _Kill _Last _Process" + " app.force_kill_last_running" + +accels["force_kill_last_running"]+ //For Ubuntu... + " " + "
" + "
" + "" + " " + " _Window" + "
" + " " + " _Next _Tab" + " app.next_tab" + +accels["next_tab"]+ //For Ubuntu... + " " + " " + " _Previous _Tab" + " app.previous_tab" + +accels["previous_tab"]+ //For Ubuntu... + " " + "
" + "
" + " " + " _Close _Tab" + " app.close_tab" + +accels["close_tab"]+ //For Ubuntu... + " " + "
" + "
" + "
" + "
"; + // std::stringstream ss; + // ss << ui_xml; + // boost::property_tree::ptree ptree; + try { + // boost::property_tree::read_xml(ss, ptree, boost::property_tree::xml_parser::trim_whitespace); + // auto &xml_interface = ptree.get_child("interface"); + // auto menu_range = xml_interface.equal_range("menu"); + // boost::property_tree::ptree * menu = nullptr; + // for(auto &it = menu_range.first; it!=menu_range.second; it++) { + // if((it->second.get_child(".id")).get_value() == "window-menu"){ + // menu = &it->second; + // } + // } + // if(menu != nullptr) { + // PythonInterpreter::get(); + // for (auto &plugin : plugin_entries) { + // add_sections(*menu, plugin, accels); + // } + // } + // ss = std::stringstream(); + // boost::property_tree::write_xml(ss, ptree, boost::property_tree::xml_parser::trim_whitespace); + // ui_xml = ss.str(); + // menu = nullptr; + builder = Gtk::Builder::create_from_string(ui_xml); + auto object = builder->get_object("juci-menu"); + menu_refrences["juci_menu"] = Glib::RefPtr::cast_dynamic(object); + object = builder->get_object("window-menu"); + menu_refrences["window_menu"] = Glib::RefPtr::cast_dynamic(object); + menu_refrences["plugin_menu"] = Gio::Menu::create(); + menu_refrences["window_menu"]->insert_submenu(5, "_Plugins", menu_refrences["plugin_menu"]); + } catch (const std::exception &ex) { + std::cerr << "building menu failed: " << ex.what(); } } -void Menu::build() { - builder = Gtk::Builder::create(); - - try { - builder->add_from_string(ui_xml); - auto object = Menu::get().builder->get_object("juci-menu"); - juci_menu = Glib::RefPtr::cast_dynamic(object); - object = Menu::get().builder->get_object("window-menu"); - window_menu = Glib::RefPtr::cast_dynamic(object); - } - catch (const Glib::Error &ex) { - std::cerr << "building menu failed: " << ex.what(); +void Menu::add_sections(boost::property_tree::ptree &xml_menus, boost::property_tree::ptree &menu_elements, const std::unordered_map &accels){ + boost::property_tree::ptree empty; + for(auto &element:menu_elements){ + auto label=element.second.get("label", ""); + auto &sub_menu_elements=element.second.get_child("menu_elements", empty); + if(sub_menu_elements.empty()){ // item + auto action=element.second.get("action", ""); + auto keybinding=element.second.get("keybinding", ""); + if(!action.empty()&&!keybinding.empty()){ + Config::get().menu.keys[action] = keybinding; + } + if(!label.empty() && !action.empty()){ + add_action(action, [action](){ +// auto res = PythonInterpreter::get().exec(action); +// res.dec_ref(); + }); + auto accel = accels.find(label); + auto items=xml_menus.equal_range("item"); + bool item_exists=false; + for(auto &it=items.first; it!=items.second; it++){ + auto item_label=(it->second.get_child("attribute")).get_value(); + if(item_label==label){ + item_exists=true; + } + } + if(!item_exists) + xml_menus.add_child("item",generate_item(label,action,accel!=accels.end()?accel->second:"")); + } + if(label.empty() && action.empty()){ + Terminal::get().print("Couldn't parse json, item has no action or label\n"); + continue; + } + }else{ + // for(auto &sub_menu_element:sub_menu_elements){ + // if(!label.empty()){ + // auto submenus=xml_menus.equal_range("submenu"); + // boost::property_tree::ptree *xml_submenu=nullptr; + // for(auto &it=submenus.first;it!=submenus.second;it++){ + // auto submenu_label=(it->second.get_child("attribute")).get_value(); + // if(label==submenu_label){ + // xml_submenu=&it->second; + // break; + // } + // } + // if(xml_submenu==nullptr) + // xml_submenu=&xml_menus.add_child("submenu", generate_submenu(label)); + // add_sections(*xml_submenu, sub_menu_elements, accels); + // }else{ + // Terminal::get().print("Couldn't parse json, item has no action or label\n"); + // continue; + // } + // } + } } } diff --git a/src/menu.h b/src/menu.h index 9e3fc563..de789414 100644 --- a/src/menu.h +++ b/src/menu.h @@ -4,27 +4,29 @@ #include #include #include +#include class Menu { private: Menu(); + public: static Menu &get() { static Menu singleton; return singleton; } - + boost::property_tree::ptree generate_submenu(const std::string &label); + boost::property_tree::ptree generate_item(const std::string &label, const std::string &action, const std::string &accel); void add_action(const std::string &name, std::function action); - std::unordered_map > actions; + void add_sections(boost::property_tree::ptree &ptree, boost::property_tree::ptree &menu, const std::unordered_map &accels); void set_keys(); - + std::vector plugin_entries; + std::unordered_map > actions; void build(); - - Glib::RefPtr juci_menu; - Glib::RefPtr window_menu; - + std::unordered_map> menu_refrences; private: Glib::RefPtr builder; std::string ui_xml; }; + #endif // JUCI_MENU_H_ diff --git a/src/notebook.cc b/src/notebook.cc index fdb70e7f..699a319d 100644 --- a/src/notebook.cc +++ b/src/notebook.cc @@ -64,12 +64,18 @@ int Notebook::size() { } Source::View* Notebook::get_view(int page) { - return source_views.at(get_index(page)); + size_t index=get_index(page); + if(index!=static_cast(-1)) + return source_views[index]; + else + return nullptr; } size_t Notebook::get_index(int page) { + if(page==-1) + return -1; for(size_t c=0;c #include "gtkmm.h" #include "source.h" #include "source_clang.h" diff --git a/src/python_api.cc b/src/python_api.cc new file mode 100644 index 00000000..8010848e --- /dev/null +++ b/src/python_api.cc @@ -0,0 +1,170 @@ +#include "python_api.h" +#include "python_interpreter.h" +#include "notebook.h" +#include "config.h" +#include "juci.h" +#include "menu.h" +#include "directories.h" +#include "window.h" +#include + +template pybind11::object pyobject_from_gobj(T ptr){ + if(G_IS_OBJECT(ptr)){ + auto obj=G_OBJECT(ptr); + if(obj) + return pybind11::object(pygobject_new(obj), true); + } + return pybind11::object(Py_None, false); +} + +template pybind11::object pyobject_from_refptr_type(const T &ptr){ + if(ptr) + return pyobject_from_gobj(ptr->gobj()); + pybind11::object(Py_None, false); +} + +extern "C" PYBIND11_EXPORT PyObject *init_juci_api() { + + pybind11::module api("libjuci", "Python API for juCi++"); + + pybind11::module(pygobject_init(-1,-1,-1), false); + + api.def_submodule("beta") + .def("get_notebook", + [](){ + auto gtk_notebook=reinterpret_cast(Notebook::get().gobj()); + return pyobject_from_gobj(gtk_notebook); + }, pybind11::return_value_policy::reference_internal + ) + .def("get_menu_from_name", + [](const std::string &menu_name){ + auto &menu_refrences=Menu::get().menu_refrences; + auto res_menu=menu_refrences.find(menu_name); + if(res_menu!=menu_refrences.end()){ + return pyobject_from_gobj(res_menu->second->gobj()); + } + return pybind11::object(Py_None, false); + }, pybind11::return_value_policy::reference_internal + ) + .def("get_gtk_application", + [](){ + auto g_application=g_application_get_default(); + auto gio_application=Glib::wrap(g_application, true); + auto application=Glib::RefPtr::cast_static(gio_application); + auto gtk_application=reinterpret_cast(application->gobj()); + return pyobject_from_gobj(gtk_application); + } + ); + api.def("get_juci_home", + [] () { + return Config::get().juci_home_path().string(); + }, + "(str) Returns the path of the juci home folder" + ); + api.def("add_menu_element", + [] (const char *json) { + boost::property_tree::ptree ptree; + std::stringstream ss; + ss << json; + try { + boost::property_tree::read_json(ss, ptree); + Menu::get().plugin_entries.emplace_back(ptree); + } catch (std::exception &ex) { + std::cerr << "There was an error while parsing json:\n" << json; + std::cerr << std::endl << ex.what() << std::endl; + } + }, + "(void) Builds a menu configured by 'json'", + pybind11::arg("(str) json") + ); + + api.def_submodule("directories") + .def("open", + [] (std::string dir) { // ex. libjuci.directories.open("/home/") + boost::filesystem::path path(dir); + if(boost::filesystem::is_directory(path)) + Directories::get().open(path); + if(boost::filesystem::is_regular_file(path)) + Notebook::get().open(path); + }, + "(void) Opens 'dir' in file tree", + pybind11::arg("(str) dir") + ) + .def("update", + [](){ + Directories::get().update(); + }, + "(void) Updates the file tree" + ) + .def("get_directories", + [](){ + auto view=reinterpret_cast(Directories::get().gobj()); + return pyobject_from_gobj(view); + }, pybind11::return_value_policy::reference_internal + ); + + api.def_submodule("editor") + .def("get_file_name", + [] () -> std::string { + auto view = Notebook::get().get_current_view(); + if (view != nullptr) { + return view->file_path.string(); + } + return ""; + }, + "(str) Returns the current open file. If no file is open it returns empty a string" + ) + .def("get_tab_char_and_size", + [](){ + auto view = Notebook::get().get_current_view(); + if (view != nullptr) + return view->get_tab_char_and_size(); + return std::make_pair(0,0); + } + ) + .def("get_current_gtk_text_buffer", + [](){ + auto view=Notebook::get().get_current_view(); + if(view){ + auto gtk_buffer=reinterpret_cast(view->get_buffer()->gobj()); + return pyobject_from_gobj(gtk_buffer); + } + return pybind11::object(Py_None, false); + },pybind11::return_value_policy::reference_internal + ) + ; + + api.def_submodule("terminal") + .def("println", + [] (std::string message) { + return Terminal::get().print(message + "\n"); //TODO alternative for print, python key word + }, + "Returns int, Prints 'message' to terminal", //TODO what does the return represent? + pybind11::arg("str message") + ) + .def("get_textview", + [](){ + return pyobject_from_gobj(Terminal::get().gobj()); + }, pybind11::return_value_policy::reference_internal + ) + ; + +// api.def("", +// [](const char *json){ +// boost::property_tree::ptree menu_elements; +// std::stringstream ss; +// ss << json; +// try{ +// boost::property_tree::read_json(ss, menu_elements); +// }catch(std::exception &ex){ +// std::cerr << "Error while parsing json" << std::endl; +// return; +// } +// for(auto &element:menu_elements){ +// +// } +// } +// ); + + return api.ptr(); +} diff --git a/src/python_api.h b/src/python_api.h new file mode 100644 index 00000000..bbaaf019 --- /dev/null +++ b/src/python_api.h @@ -0,0 +1,8 @@ +#ifndef JUCI_PYTHON_API_ +#define JUCI_PYTHON_API_ + +#include + +extern "C" PYBIND11_EXPORT PyObject * init_juci_api(); + +#endif // JUCI_PYTHON_API_ \ No newline at end of file diff --git a/src/python_interpreter.cc b/src/python_interpreter.cc new file mode 100644 index 00000000..163e704f --- /dev/null +++ b/src/python_interpreter.cc @@ -0,0 +1,153 @@ +#include "python_interpreter.h" +#include "python_api.h" +#include "config.h" +#include "terminal.h" +#include "juci.h" + +PythonInterpreter& PythonInterpreter::get(){ + static PythonInterpreter s; + return s; +} + +bool PythonInterpreter::reload(const std::string &module_name){ + pybind11::module module(PyImport_AddModule(module_name.c_str()), true); + if(module){ + pybind11::module reload(PyImport_ReloadModule(module.ptr()), false); + if(reload){ + return true; + } + } + handle_py_exception(); + return false; +} + +pybind11::module PythonInterpreter::import(const std::string &module_name){ + pybind11::module module(PyImport_ImportModule(module_name.c_str()), true); + if(module){ + return module; + } + handle_py_exception(); + return pybind11::module(Py_None, false); +} + +PythonInterpreter::PythonInterpreter(){ +#ifdef _WIN32 + auto root_path=Config::get().terminal.msys2_mingw_path; + append_path(root_path/"include/python3.5m"); + append_path(root_path/"lib/python3.5"); + long long unsigned size = 0L; +#else + long unsigned size = 0L; +#endif + Config::get().load(); + append_path(Config::get().python.site_packages); + auto plugin_path=Config::get().python.plugin_directory; + append_path(plugin_path); + PyImport_AppendInittab("libjuci",init_juci_api); + Py_Initialize(); + argv=Py_DecodeLocale("",&size); + PySys_SetArgv(0,&argv); + boost::filesystem::directory_iterator end_it; + for(boost::filesystem::directory_iterator it(plugin_path);it!=end_it;it++){ + auto module_name=it->path().stem().generic_string(); + if(module_name!="__pycache__"){ + auto module=import(module_name); + } + } +} + +PythonInterpreter::~PythonInterpreter(){ + handle_py_exception(); + if(Py_IsInitialized()) + Py_Finalize(); +} + +void PythonInterpreter::append_path(const boost::filesystem::path &path){ + std::wstring res(Py_GetPath()); + if(!res.empty()) +#ifdef _WIN32 + res += ';'; +#else + res += ':'; +#endif + res += path.generic_wstring(); + Py_SetPath(res.c_str()); +} + +pybind11::object PythonInterpreter::exec(const std::string &method_qualifier){ + auto pos = method_qualifier.rfind('.'); + if (pos == std::string::npos) + return pybind11::object(nullptr, false); + auto module_name=method_qualifier.substr(0,pos); + auto method=method_qualifier.substr(module_name.length()+1,method_qualifier.size()); + auto module=pybind11::module(PyImport_AddModule(module_name.c_str()), true); + if(module){ + pybind11::handle func(module.attr(method.c_str())); + if(func && PyCallable_Check(func.ptr())){ + try{ + return func.call(); + }catch(const std::exception &ex){ + Terminal::get().print(std::string(ex.what()) + "\n"); + } + } + } + handle_py_exception(); + return pybind11::object(nullptr, false); +} + +void PythonInterpreter::handle_py_exception(bool suppress_error_messages){ + pybind11::handle error(PyErr_Occurred()); + if(error){ + PyObject *exception,*value,*traceback; + PyErr_Fetch(&exception,&value,&traceback); + PyErr_NormalizeException(&exception,&value,&traceback); + pybind11::object py_exception(exception,false); + pybind11::object py_value(value,false); + pybind11::object py_traceback(traceback,false); + if(suppress_error_messages){ + return; + } + std::stringstream str; + if(PyErr_GivenExceptionMatches(py_exception.ptr(),PyExc_SyntaxError)){ + std::string error_msgs,error; + int line_number=0,offset=0; + if(parse_syntax_error(py_value,error_msgs,error,line_number,offset)) + str << error_msgs << " (" << line_number << ":" << offset << "):\n" << error; + else + str << "An error occured while trying to parse SyntaxError\n"; + } + else if(PyErr_GivenExceptionMatches(py_exception.ptr(),PyExc_AttributeError)) + str << "AttributeError: " << std::string(py_value.str()) << "\n"; + else if(PyErr_GivenExceptionMatches(py_exception.ptr(),PyExc_ImportError)) + str << "ImportError: " << std::string(py_value.str()) << "\n"; + else + str << std::string(py_exception.str()) << "\n" << std::string(py_value.str()) << "\n"; + if(Terminal::get().is_visible()) + Terminal::get().print(str.str()); + else + std::cerr << str.rdbuf(); + } +} + +bool PythonInterpreter::parse_syntax_error(pybind11::object &py_value,std::string &error_msg,std::string &error,int &line_number,int &offset){ + _Py_IDENTIFIER(msg); // declares PyID_msg + _Py_IDENTIFIER(lineno); + _Py_IDENTIFIER(offset); + _Py_IDENTIFIER(text); + pybind11::str py_error_msg(_PyObject_GetAttrId(py_value.ptr(),&PyId_msg),false); + pybind11::str py_error_text(_PyObject_GetAttrId(py_value.ptr(),&PyId_text),false); + pybind11::object py_line_number(_PyObject_GetAttrId(py_value.ptr(),&PyId_lineno),false); + pybind11::object py_line_offset(_PyObject_GetAttrId(py_value.ptr(),&PyId_offset),false); + if(py_line_number.ptr()!=Py_None && py_line_offset.ptr()!=Py_None && py_error_msg.ptr()!=Py_None && py_error_text.ptr()!=Py_None){ + line_number=PyLong_AsLong(py_line_number.ptr()); // TODO these pymethod can produce pyerrors + offset=PyLong_AsLong(py_line_offset.ptr()); + error_msg=std::string(py_error_msg); + error=std::string(py_error_text); + return true; + } + error_msg=""; + error=""; + line_number=0; + offset=0; + return false; +} diff --git a/src/python_interpreter.h b/src/python_interpreter.h new file mode 100644 index 00000000..797e60d2 --- /dev/null +++ b/src/python_interpreter.h @@ -0,0 +1,25 @@ +#ifndef JUCI_API_H_ +#define JUCI_API_H_ + +#include +#include +#include + +class PythonInterpreter { +public: + ~PythonInterpreter(); + static PythonInterpreter& get(); + void init(); + void append_path(const boost::filesystem::path &path); + pybind11::object exec(const std::string &method_qualifier); + bool reload(const std::string &module_name); + bool parse_syntax_error(pybind11::object &py_value,std::string &error_msgs,std::string &error,int &line_number,int &offset); + void handle_py_exception(bool suppress_error_messages=false); + pybind11::module import(const std::string &module_name); +private: + PythonInterpreter(); + wchar_t *argv; +}; + + +#endif // JUCI_API_H_ diff --git a/src/terminal.h b/src/terminal.h index dd74ad99..02bcaec5 100644 --- a/src/terminal.h +++ b/src/terminal.h @@ -19,6 +19,7 @@ class Terminal : public Gtk::TextView { ~InProgress(); void done(const std::string& msg); void cancel(const std::string& msg); + private: void start(const std::string& msg); size_t line_nr; @@ -26,7 +27,6 @@ class Terminal : public Gtk::TextView { std::thread wait_thread; }; - private: Terminal(); public: diff --git a/src/window.cc b/src/window.cc index c20fed22..27feb746 100644 --- a/src/window.cc +++ b/src/window.cc @@ -3,9 +3,9 @@ #include "config.h" #include "menu.h" #include "directories.h" -//#include "api.h" #include "dialogs.h" #include "filesystem.h" +#include "python_interpreter.h" #include "project.h" #include "entrybox.h" @@ -32,11 +32,9 @@ Window::Window() : notebook(Notebook::get()) { configure(); set_default_size(Config::get().window.default_size.first, Config::get().window.default_size.second); - - //PluginApi(&this->notebook, &this->menu); - + add(vpaned); - + directories_scrolled_window.add(Directories::get()); directory_and_notebook_panes.pack1(directories_scrolled_window, Gtk::SHRINK); notebook_vbox.pack_start(notebook); @@ -45,10 +43,10 @@ Window::Window() : notebook(Notebook::get()) { directory_and_notebook_panes.set_position(static_cast(0.2*Config::get().window.default_size.first)); vpaned.set_position(static_cast(0.75*Config::get().window.default_size.second)); vpaned.pack1(directory_and_notebook_panes, true, false); - + terminal_scrolled_window.add(Terminal::get()); terminal_vbox.pack_start(terminal_scrolled_window); - + info_and_status_hbox.pack_start(notebook.info, Gtk::PACK_SHRINK); #if GTK_VERSION_GE(3, 12) @@ -60,7 +58,7 @@ Window::Window() : notebook(Notebook::get()) { info_and_status_hbox.pack_end(notebook.status, Gtk::PACK_SHRINK); terminal_vbox.pack_end(info_and_status_hbox, Gtk::PACK_SHRINK); vpaned.pack2(terminal_vbox, true, true); - + show_all_children(); Directories::get().on_row_activated=[this](const boost::filesystem::path &path) { @@ -101,16 +99,16 @@ Window::Window() : notebook(Notebook::get()) { } activate_menu_items(); - + Directories::get().select(view->file_path); - + if(view->full_reparse_needed) { if(!view->full_reparse()) Terminal::get().async_print("Error: failed to reparse "+view->file_path.string()+". Please reopen the file manually.\n", true); } else if(view->soft_reparse_needed) view->soft_reparse(); - + view->set_status(view->status); view->set_info(view->info); } @@ -118,14 +116,14 @@ Window::Window() : notebook(Notebook::get()) { notebook.signal_page_removed().connect([this](Gtk::Widget* page, guint page_num) { EntryBox::get().hide(); }); - + about.signal_response().connect([this](int d){ about.hide(); }); about.set_version(Config::get().window.version); about.set_authors({"(in order of appearance)", - "Ted Johan Kristoffersen", + "Ted Johan Kristoffersen", "Jørgen Lien Sellæg", "Geir Morten Larsen", "Ole Christian Eidheim"}); @@ -135,6 +133,7 @@ Window::Window() : notebook(Notebook::get()) { about.set_license_type(Gtk::License::LICENSE_MIT_X11); about.set_transient_for(*this); JDEBUG("end"); + PythonInterpreter::get(); } // Window constructor void Window::configure() { @@ -150,7 +149,7 @@ void Window::configure() { void Window::set_menu_actions() { auto &menu = Menu::get(); - + menu.add_action("about", [this]() { about.show(); about.present(); @@ -161,7 +160,7 @@ void Window::set_menu_actions() { menu.add_action("quit", [this]() { close(); }); - + menu.add_action("new_file", [this]() { boost::filesystem::path path = Dialog::new_file(notebook.get_current_folder()); if(path!="") { @@ -227,7 +226,7 @@ void Window::set_menu_actions() { Terminal::get().print("Error: Could not create project "+project_path.string()+"\n", true); } }); - + menu.add_action("open_file", [this]() { auto path=Dialog::open_file(notebook.get_current_folder()); if(path!="") @@ -238,18 +237,30 @@ void Window::set_menu_actions() { if (path!="" && boost::filesystem::exists(path)) Directories::get().open(path); }); - + 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==Config::get().juci_home_path()/"config"/"config.json") { + const auto file_path = notebook.get_current_view()->file_path; + if(file_path==Config::get().juci_home_path()/"config"/"config.json") { configure(); for(int c=0;cconfigure(); notebook.configure(c); } } + auto parent = file_path; + while(parent.has_parent_path()) { + if(parent == Config::get().python.plugin_directory) { + auto stem = notebook.get_current_view()->file_path.stem().generic_string(); + if(PythonInterpreter::get().reload(stem)){ + Terminal::get().print("Python module "+stem + " has been reloaded \n"); + } + break; + } + parent = parent.parent_path(); + } } } } @@ -272,7 +283,7 @@ void Window::set_menu_actions() { } } }); - + menu.add_action("edit_undo", [this]() { if(notebook.get_current_page()!=-1) { auto undo_manager = notebook.get_current_view()->get_source_buffer()->get_undo_manager(); @@ -291,7 +302,7 @@ void Window::set_menu_actions() { } } }); - + menu.add_action("edit_cut", [this]() { auto widget=get_focus(); if(auto entry=dynamic_cast(widget)) @@ -313,11 +324,11 @@ void Window::set_menu_actions() { 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) notebook.get_current_view()->spellcheck(); @@ -330,7 +341,7 @@ void Window::set_menu_actions() { if(notebook.get_current_page()!=-1) notebook.get_current_view()->goto_next_spellcheck_error(); }); - + menu.add_action("source_indentation_set_buffer_tab", [this]() { set_tab_entry(); }); @@ -338,22 +349,21 @@ void Window::set_menu_actions() { if(notebook.get_current_page()!=-1 && notebook.get_current_view()->auto_indent) notebook.get_current_view()->auto_indent(); }); - + menu.add_action("source_goto_line", [this]() { goto_line_entry(); }); menu.add_action("source_center_cursor", [this]() { - if(notebook.get_current_page()!=-1) { + if(notebook.get_current_page()!=-1){ auto view=notebook.get_current_view(); - view->scroll_to_cursor_delayed(view, true, false); } }); - + 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(); + auto data=notebook.get_current_view()->get_token_data(); if(data.size()>0) { auto documentation_search=Config::get().source.documentation_searches.find(data[0]); if(documentation_search!=Config::get().source.documentation_searches.end()) { @@ -373,7 +383,7 @@ void Window::set_menu_actions() { query=documentation_search->second.queries.find("@empty"); if(query==documentation_search->second.queries.end()) query=documentation_search->second.queries.find("@any"); - + if(query!=documentation_search->second.queries.end()) { std::string uri=query->second+token_query; #ifdef __APPLE__ @@ -390,7 +400,7 @@ void Window::set_menu_actions() { } } }); - + menu.add_action("source_goto_declaration", [this]() { if(notebook.get_current_page()!=-1) { if(notebook.get_current_view()->get_declaration_location) { @@ -411,8 +421,7 @@ void Window::set_menu_actions() { while(!iter.ends_line()) iter.forward_char(); auto end_line_index=iter.get_line_index(); - index=std::min(index, end_line_index); - + index=std::min(index, end_line_index); view->get_buffer()->place_cursor(view->get_buffer()->get_iter_at_line_index(line, index)); view->scroll_to_cursor_delayed(view, true, false); } @@ -429,7 +438,7 @@ void Window::set_menu_actions() { auto iter=current_view->get_iter_for_dialog(); current_view->selection_dialog=std::unique_ptr(new SelectionDialog(*current_view, current_view->get_buffer()->create_mark(iter), true, true)); auto rows=std::make_shared >(); - + //First add usages in current file auto usages=current_view->get_usages(token); for(auto &usage: usages) { @@ -453,7 +462,7 @@ void Window::set_menu_actions() { } } } - + if(rows->size()==0) return; current_view->selection_dialog->on_select=[this, rows](const std::string& selected, bool hide_window) { @@ -484,7 +493,7 @@ void Window::set_menu_actions() { 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) { @@ -498,8 +507,7 @@ void Window::set_menu_actions() { notebook.get_current_view()->apply_fix_its(); } } - }); - + }); menu.add_action("project_set_run_arguments", [this]() { auto project_language=Project::get_language(); auto run_arguments=std::make_shared >(project_language->get_run_arguments()); @@ -546,7 +554,7 @@ void Window::set_menu_actions() { Project::current_language->compile(); }); - + menu.add_action("run_command", [this]() { EntryBox::get().clear(); EntryBox::get().labels.emplace_back(); @@ -560,7 +568,7 @@ void Window::set_menu_actions() { last_run_command=content; auto run_path=notebook.get_current_folder(); Terminal::get().async_print("Running: "+content+'\n'); - + Terminal::get().async_process(content, run_path, [this, content](int exit_status){ Terminal::get().async_print(content+" returned: "+std::to_string(exit_status)+'\n'); }); @@ -574,7 +582,7 @@ void Window::set_menu_actions() { }); EntryBox::get().show(); }); - + menu.add_action("kill_last_running", [this]() { Terminal::get().kill_last_async_process(); }); @@ -738,7 +746,7 @@ void Window::set_menu_actions() { else { notebook.status.set_text(""); notebook.info.set_text(""); - + activate_menu_items(false); } }); @@ -1010,7 +1018,6 @@ void Window::goto_line_entry() { auto line = stoi(content); if(line>0 && line<=view->get_buffer()->get_line_count()) { line--; - view->get_buffer()->place_cursor(view->get_buffer()->get_iter_at_line(line)); view->scroll_to_cursor_delayed(view, true, false); }