Browse Source

Resolved conflicts in #68.

merge-requests/365/head
eidheim 10 years ago
parent
commit
17e45b1e63
  1. 3
      .gitmodules
  2. 40
      README.md
  3. 36
      docs/install.md
  4. 1
      libclangmm
  5. 86
      src/CMakeLists.txt
  6. 6
      src/cmake.cc
  7. 9
      src/config.cc
  8. 6
      src/entrybox.cc
  9. 2
      src/entrybox.h
  10. 19
      src/files.h
  11. 8
      src/menu.cc
  12. 32
      src/notebook.cc
  13. 2
      src/notebook.h
  14. 1332
      src/source.cc
  15. 169
      src/source.h
  16. 1236
      src/source_clang.cc
  17. 128
      src/source_clang.h
  18. 141
      src/window.cc
  19. 2
      src/window.h

3
.gitmodules vendored

@ -0,0 +1,3 @@
[submodule "libclangmm"]
path = libclangmm
url = https://github.com/eidheim/libclangmm.git

40
README.md

@ -1,33 +1,41 @@
# juCi++
###### a lightweight C++-IDE with support for C++11 and C++14.
###### a lightweight platform independent C++-IDE with support for C++11 and C++14.
## About
Current IDEs struggle with C++ support due to the complexity of
the programming language. juCI++, however, is designed especially
towards libclang with speed in mind.
towards libclang with speed and ease of use in mind.
## Features
* Fast and responsive
* Platform independent
* Fast and responsive (written in C++)
* Syntax highlighting (even C++11/14, and more than 100 other file types)
* C++ warnings and errors on the fly
* Fast C++ autocomletion (even external libraries)
* C++ Fix-its
* Automated CMake processing
* Fast C++ autocomletion (including external libraries)
* Keyword and buffer autocomletion for other file types
* Tooltips showing type information and doxygen documentation
* Refactoring across files
* Highlighting of similar types
* Documentation search
* Spell checking depending on file context
* Basic editor functionality
* Write your own plugins in python (disabled at the moment)
* Run shell commands within JuCi++, even on Windows
* Regex search and replace
* Smart paste, keys and indentation
* Source minimap
* Full UTF-8 support
See [enhancements](https://github.com/cppit/jucipp/labels/enhancement) for planned features.
## Dependencies ##
* libboost-filesystem-dev
* libboost-log-dev
* libboost-test-dev
* libboost-thread-dev
* libboost-system-dev
* libgtkmm-3.0-dev
* libgtksourceview2.0-dev
* libgtksourceviewmm-3.0-dev
* libaspell-dev
* libclang-dev
* boost-filesystem
* boost-log
* boost-thread
* boost-system
* gtkmm-3.0
* gtksourceviewmm-3.0
* aspell
* libclang
* [libclangmm](http://github.com/cppit/libclangmm/)
## Installation ##

36
docs/install.md

@ -1,13 +1,14 @@
# juCi++
## Installation guide ##
Before installation, please install libclangmm, see [installation guide](http://github.com/cppit/libclangmm/blob/master/docs/install.md).
# juCi++ Installation Guide
## Debian/Ubuntu 15
Install dependencies:
```sh
sudo apt-get install pkg-config libboost-system-dev libboost-thread-dev libboost-filesystem-dev libboost-log-dev libgtkmm-3.0-dev libgtksourceviewmm-3.0-dev aspell-en libaspell-dev git
sudo apt-get install git cmake make g++ libclang-dev pkg-config libboost-system-dev libboost-thread-dev libboost-filesystem-dev libboost-log-dev libgtkmm-3.0-dev libgtksourceviewmm-3.0-dev aspell-en libaspell-dev
```
Get juCi++ source, compile and install:
```sh
git clone http://github.com/cppit/jucipp.git
git clone --recursive http://github.com/cppit/jucipp
cd jucipp
cmake .
make
@ -15,15 +16,18 @@ sudo make install
```
## Ubuntu 14/Linux Mint 17
Install dependencies:
```sh
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
sudo apt-get update
sudo apt-get install g++-4.9
sudo apt-get remove g++-4.8
sudo apt-get install pkg-config libboost-system1.55-dev libboost-thread1.55-dev libboost-filesystem1.55-dev libboost-log1.55-dev libgtkmm-3.0-dev libgtksourceviewmm-3.0-dev aspell-en libaspell-dev git
sudo apt-get install git cmake make g++ libclang-3.6-dev pkg-config libboost-system1.55-dev libboost-thread1.55-dev libboost-filesystem1.55-dev libboost-log1.55-dev libgtkmm-3.0-dev libgtksourceviewmm-3.0-dev aspell-en libaspell-dev
```
Get juCi++ source, compile and install:
```sh
git clone http://github.com/cppit/jucipp.git
git clone --recursive http://github.com/cppit/jucipp
cd jucipp
cmake .
make
@ -31,12 +35,14 @@ sudo make install
```
## OS X with Homebrew (http://brew.sh/)
Install dependencies (installing llvm may take some time):
```sh
brew install pkg-config boost gtkmm3 homebrew/x11/gtksourceviewmm3 aspell git
brew install cmake --with-clang llvm pkg-config boost gtkmm3 homebrew/x11/gtksourceviewmm3 aspell
```
Get juCi++ source, compile and install:
```sh
git clone https://github.com/cppit/jucipp.git
git clone --recursive https://github.com/cppit/jucipp
cd jucipp
cmake .
make
@ -44,19 +50,15 @@ make install
```
##Windows with MSYS2 (https://msys2.github.io/)
Install dependencies (replace x86_64 with i686 for 32-bit MSYS2 installs):
Install dependencies (replace `x86_64` with `i686` for 32-bit MSYS2 installs):
```sh
pacman -S patch autoconf automake-wrapper mingw-w64-x86_64-gtkmm3 mingw-w64-x86_64-gtksourceviewmm3 mingw-w64-x86_64-boost mingw-w64-x86_64-aspell mingw-w64-x86_64-aspell-en git
pacman -S git mingw-w64-x86_64-cmake make mingw-w64-x86_64-toolchain mingw-w64-x86_64-clang mingw-w64-x86_64-gtkmm3 mingw-w64-x86_64-gtksourceviewmm3 mingw-w64-x86_64-boost mingw-w64-x86_64-aspell mingw-w64-x86_64-aspell-en
```
Get juCi++ source:
Get juCi++ source, compile and install (replace `mingw64` with `mingw32` for 32-bit MSYS2 installs):
```sh
git clone https://github.com/cppit/jucipp.git
git clone --recursive https://github.com/cppit/jucipp
cd jucipp
```
Compile and install juCi++ source (replace mingw64 with mingw32 for 32-bit MSYS2 installs):
```sh
cmake -G"MSYS Makefiles" -DCMAKE_INSTALL_PREFIX=/mingw64 .
make
make install

1
libclangmm

@ -0,0 +1 @@
Subproject commit e060dec32bb8306eff6f9114092cdbefe8fea5fb

86
src/CMakeLists.txt

@ -12,47 +12,16 @@ endif()
INCLUDE(FindPkgConfig)
set(validation true)
function(install_help APPLE UNIX WINDOWS)
message("Install package with:")
if(UNIX)
if(APPLE)
message("brew install ${APPLE}")
else()
message("sudo apt-get install ${UNIX}")
endif(APPLE)
endif(UNIX)
if(WINDOWS)
#message("choco install ${WINDOWS}") #Removed this for the time being
endif(WINDOWS)
endfunction(install_help)
function(validate FOUND APPLE UNIX WINDOWS)
if(!${FOUND})
set(validation false)
install_help(${APPLE} ${UNIX} ${WINDOWS})
endif()
endfunction(validate)
find_package(LibClangmm)
validate(${LCL_FOUND} "clangmm" "clangmm" "clangmm")
find_package(LibClang)
validate(${LIBCLANG_FOUND} "clang" "libclang-dev" "llvm")
find_package(LibClang REQUIRED)
#find_package(PythonLibs 2.7)
#validate(${PYTHONLIBS_FOUND} "python" "libpython-dev" "python")
#find_package(Boost 1.55 COMPONENTS python thread log system filesystem REQUIRED)
find_package(Boost 1.55 COMPONENTS thread log system filesystem REQUIRED)
validate(${Boost_FOUND} "boost" "libboost-all-dev" "boost")
pkg_check_modules(GTKMM gtkmm-3.0) # The name GTKMM is set here for the variables abouve
validate(${GTKMM_FOUND} "gtkmm" "libgtkmm-dev" "gtkmm")
pkg_check_modules(GTKMM gtkmm-3.0 REQUIRED) # The name GTKMM is set here for the variables abouve
pkg_check_modules(GTKSVMM gtksourceviewmm-3.0)
validate(${GTKSVMM_FOUND} "gtksvmm" "libgtksvmm-dev" "gtkmmsv")
pkg_check_modules(GTKSVMM gtksourceviewmm-3.0 REQUIRED)
find_package(ASPELL REQUIRED)
@ -62,6 +31,8 @@ set(source_files juci.h
menu.cc
source.h
source.cc
source_clang.h
source_clang.cc
selectiondialog.h
selectiondialog.cc
config.h
@ -85,7 +56,22 @@ set(source_files juci.h
singletons.h
singletons.cc
cmake.h
cmake.cc)
cmake.cc
../libclangmm/src/CodeCompleteResults.cc
../libclangmm/src/CompilationDatabase.cc
../libclangmm/src/CompileCommand.cc
../libclangmm/src/CompileCommands.cc
../libclangmm/src/CompletionString.cc
../libclangmm/src/Cursor.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/Utility.cc)
if(MSYS)
list(APPEND source_files terminal_win.cc)
@ -102,30 +88,30 @@ else()
list(APPEND source_files dialogs.cc)
endif()
if(${validation})
add_executable(${project_name} ${source_files})
add_executable(${project_name} ${source_files})
# add_library(${module} SHARED
# api
# api_ext)
include_directories(
include_directories(
${Boost_INCLUDE_DIRS}
# ${PYTHON_INCLUDE_DIRS}
${GTKMM_INCLUDE_DIRS}
${GTKSVMM_INCLUDE_DIRS}
${LCL_INCLUDE_DIRS}
${DIALOGS_INCLUDE_DIRS}
${LIBCLANG_INCLUDE_DIRS}
${ASPELL_INCLUDE_DIR})
${ASPELL_INCLUDE_DIR}
${DIALOGS_INCLUDE_DIRS}
../libclangmm/src
)
link_directories(
link_directories(
${GTKMM_LIBRARY_DIRS}
${GTKSVMM_LIBRARY_DIRS}
${Boost_LIBRARY_DIRS}
# ${PYTHON_INCLUDE_DIRS}
${LCL_LIBRARY_DIRS}
${LIBCLANG_LIBRARY_DIRS})
${LIBCLANG_LIBRARY_DIRS}
)
# set_target_properties(${module}
# PROPERTIES PREFIX ""
@ -133,21 +119,19 @@ if(${validation})
# target_link_libraries(${module} ${PYTHON_LIBRARIES} ${Boost_LIBRARIES})
# target_link_libraries(${module} ${Boost_LIBRARIES})
target_link_libraries(${project_name}
target_link_libraries(${project_name}
${LIBCLANG_LIBRARIES}
${LCL_LIBRARIES}
${GTKMM_LIBRARIES}
${GTKSVMM_LIBRARIES}
${Boost_LIBRARIES}
${ASPELL_LIBRARIES}
${DIALOGS_LIBRARIES}
# ${PYTHON_LIBRARIES}
)
)
# install(TARGETS ${project_name} ${module}
install(TARGETS ${project_name}
install(TARGETS ${project_name}
RUNTIME DESTINATION bin
# LIBRARY DESTINATION ${lib_install_path}
)
endif(${validation})
)

6
src/cmake.cc

@ -142,11 +142,11 @@ void CMake::find_variables() {
const std::regex set_regex("^ *set *\\( *([A-Za-z_][A-Za-z_0-9]*) +(.*)\\) *$");
std::smatch sm;
if(std::regex_match(line, sm, set_regex)) {
std::string data=sm[2];
auto data=sm[2].str();
while(data.size()>0 && data.back()==' ')
data.pop_back();
parse_variable_parameters(data);
variables[sm[1]]=data;
variables[sm[1].str()]=data;
}
}
pos=end_line+1;
@ -264,7 +264,7 @@ std::vector<std::pair<boost::filesystem::path, std::vector<std::string> > > CMak
const std::regex function_regex("^ *"+name+" *\\( *(.*)\\) *$");
std::smatch sm;
if(std::regex_match(line, sm, function_regex)) {
std::string data=sm[1];
auto data=sm[1].str();
while(data.size()>0 && data.back()==' ')
data.pop_back();
auto parameters=get_function_parameters(data);

9
src/config.cc

@ -134,6 +134,15 @@ void MainConfig::GenerateSource() {
for (auto &i : source_json.get_child("clang_types"))
source_cfg->clang_types[i.first] = i.second.get_value<std::string>();
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");
auto &queries=source_cfg->documentation_searches.find(pt_doc_search_lang.first)->second.queries;
for(auto &i: pt_doc_search_lang.second.get_child("queries")) {
queries[i.first]=i.second.get_value<std::string>();
}
}
}
void MainConfig::GenerateDirectoryFilter() {

6
src/entrybox.cc

@ -16,8 +16,9 @@ namespace sigc {
std::unordered_map<std::string, std::vector<std::string> > EntryBox::entry_histories;
EntryBox::Entry::Entry(const std::string& content, std::function<void(const std::string& content)> on_activate, unsigned length) : Gtk::Entry(), on_activate(on_activate) {
set_max_length(length);
EntryBox::Entry::Entry(const std::string& content, std::function<void(const std::string& content)> on_activate, unsigned width_chars) : Gtk::Entry(), on_activate(on_activate) {
set_max_length(0);
set_width_chars(width_chars);
set_text(content);
selected_history=0;
signal_activate().connect([this](){
@ -92,7 +93,6 @@ void EntryBox::clear() {
void EntryBox::show() {
std::vector<Gtk::Widget*> focus_chain;
for(auto& entry: entries) {
entry.set_max_length(0);
lower_box.pack_start(entry, Gtk::PACK_SHRINK);
focus_chain.emplace_back(&entry);
}

2
src/entrybox.h

@ -12,7 +12,7 @@ class EntryBox : public Gtk::Box {
public:
class Entry : public Gtk::Entry {
public:
Entry(const std::string& content="", std::function<void(const std::string& content)> on_activate=nullptr, unsigned length=50);
Entry(const std::string& content="", std::function<void(const std::string& content)> on_activate=nullptr, unsigned width_chars=-1);
std::function<void(const std::string& content)> on_activate;
private:
size_t selected_history;

19
src/files.h

@ -1,6 +1,6 @@
#include <string>
#define JUCI_VERSION "0.9.2"
#define JUCI_VERSION "0.9.3"
const std::string configjson =
"{\n"
@ -65,15 +65,20 @@ const std::string configjson =
" \"edit_undo\": \"<primary>z\",\n"
" \"edit_redo\": \"<primary><shift>z\",\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_goto_line\": \"<primary>g\",\n"
" \"source_center_cursor\": \"<primary>l\",\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"
" \"compile\": \"<primary><shift>Return\",\n"
" \"run_command\": \"<alt>Return\",\n"
@ -91,6 +96,18 @@ const std::string configjson =
#endif
" \"make_command\": \"make\"\n"
" },\n"
" \"documentation_searches\": {\n"
" \"clang\": {\n"
" \"separator\": \"::\",\n"
" \"queries\": {\n"
" \"@empty\": \"https://www.google.com/search?btnI&q=c%2B%2B+\",\n"
" \"std\": \"https://www.google.com/search?btnI&q=site:http://www.cplusplus.com/reference/+\",\n"
" \"boost\": \"https://www.google.com/search?btnI&q=site:http://www.boost.org/doc/libs/1_59_0/+\",\n"
" \"Gtk\": \"https://www.google.com/search?btnI&q=site:https://developer.gnome.org/gtkmm/stable/+\",\n"
" \"@any\": \"https://www.google.com/search?btnI&q=\"\n"
" }\n"
" }\n"
" },\n"
" \"directoryfilter\": {\n"
" \"ignore\": [\n"
" ],\n"

8
src/menu.cc

@ -51,14 +51,22 @@ Menu::Menu() {
" <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"

32
src/notebook.cc

@ -69,14 +69,10 @@ void Notebook::open(const boost::filesystem::path &file_path) {
can_read.close();
auto language=Source::guess_language(file_path);
if(language && (language->get_id()=="chdr" || language->get_id()=="cpphdr" || language->get_id()=="c" || language->get_id()=="cpp" || language->get_id()=="objc")) {
boost::filesystem::path project_path;
auto directories = Singleton::directories();
if(directories->cmake && directories->cmake->project_path!="" && file_path.generic_string().substr(0, directories->cmake->project_path.generic_string().size()+1)==directories->cmake->project_path.generic_string()+'/') {
auto directories=Singleton::directories();
if(directories->cmake && directories->cmake->project_path!="" && file_path.generic_string().substr(0, directories->cmake->project_path.generic_string().size()+1)==directories->cmake->project_path.generic_string()+'/')
project_path=directories->cmake->project_path;
if(boost::filesystem::exists(project_path.string()+"/CMakeLists.txt") && !boost::filesystem::exists(project_path.string()+"/compile_commands.json"))
CMake::create_compile_commands(project_path);
}
else {
project_path=file_path.parent_path();
CMake cmake(project_path);
@ -84,13 +80,14 @@ void Notebook::open(const boost::filesystem::path &file_path) {
project_path=cmake.project_path;
Singleton::terminal()->print("Project path for "+file_path.string()+" set to "+project_path.string()+"\n");
}
else
Singleton::terminal()->print("Error: could not find project path for "+file_path.string()+"\n");
}
if(language && (language->get_id()=="chdr" || language->get_id()=="cpphdr" || language->get_id()=="c" || language->get_id()=="cpp" || language->get_id()=="objc")) {
if(boost::filesystem::exists(project_path.string()+"/CMakeLists.txt") && !boost::filesystem::exists(project_path.string()+"/compile_commands.json"))
CMake::create_compile_commands(project_path);
source_views.emplace_back(new Source::ClangView(file_path, project_path, language));
}
else
source_views.emplace_back(new Source::GenericView(file_path, language));
source_views.emplace_back(new Source::GenericView(file_path, project_path, language));
source_views.back()->on_update_status=[this](Source::View* view, const std::string &status) {
if(get_current_page()!=-1 && get_current_view()==view)
@ -166,6 +163,7 @@ bool Notebook::save(int page, bool reparse_needed) {
if(juci::filesystem::write(view->file_path, view->get_buffer())) {
if(reparse_needed) {
if(auto clang_view=dynamic_cast<Source::ClangView*>(view)) {
if(clang_view->language->get_id()=="chdr" || clang_view->language->get_id()=="cpphdr") {
for(auto a_view: source_views) {
if(auto a_clang_view=dynamic_cast<Source::ClangView*>(a_view)) {
if(clang_view!=a_clang_view)
@ -174,18 +172,28 @@ bool Notebook::save(int page, bool reparse_needed) {
}
}
}
}
view->get_buffer()->set_modified(false);
Singleton::terminal()->print("File saved to: " +view->file_path.string()+"\n");
//If CMakeLists.txt have been modified:
//TODO: recreate cmake even without directories open?
boost::filesystem::path project_path;
if(view->file_path.filename()=="CMakeLists.txt") {
auto directories = Singleton::directories();
auto directories=Singleton::directories();
if(directories->cmake && directories->cmake->project_path!="" && view->file_path.generic_string().substr(0, directories->cmake->project_path.generic_string().size()+1)==directories->cmake->project_path.generic_string()+'/' && CMake::create_compile_commands(directories->cmake->project_path)) {
project_path=directories->cmake->project_path;
}
else {
CMake cmake(view->file_path.parent_path());
if(cmake.project_path!="" && CMake::create_compile_commands(cmake.project_path)) {
project_path=cmake.project_path;
}
}
if(project_path!="") {
for(auto source_view: source_views) {
if(auto source_clang_view=dynamic_cast<Source::ClangView*>(source_view)) {
if(directories->cmake->project_path.string()==source_clang_view->project_path) {
if(project_path==source_clang_view->project_path) {
if(source_clang_view->restart_parse())
Singleton::terminal()->async_print("Reparsing "+source_clang_view->file_path.string()+"\n");
else

2
src/notebook.h

@ -4,7 +4,7 @@
#include <iostream>
#include "gtkmm.h"
#include "source.h"
#include <boost/algorithm/string/case_conv.hpp>
#include "source_clang.h"
#include <type_traits>
#include <map>
#include <sigc++/sigc++.h>

1332
src/source.cc

File diff suppressed because it is too large Load Diff

169
src/source.h

@ -1,20 +1,13 @@
#ifndef JUCI_SOURCE_H_
#define JUCI_SOURCE_H_
#include <iostream>
#include <unordered_map>
#include <vector>
#include "gtkmm.h"
#include "clangmm.h"
#include <thread>
#include <mutex>
#include <string>
#include <atomic>
#include "gtksourceviewmm.h"
#include "terminal.h"
#include "tooltips.h"
#include "selectiondialog.h"
#include <set>
#include <regex>
#include <aspell.h>
#include <boost/property_tree/xml_parser.hpp>
@ -23,6 +16,12 @@ namespace Source {
class Config {
public:
class DocumentationSearch {
public:
std::string separator;
std::unordered_map<std::string, std::string> queries;
};
std::string style;
std::string font;
std::string spellcheck_language;
@ -37,22 +36,8 @@ namespace Source {
bool highlight_current_line;
bool show_line_numbers;
std::unordered_map<std::string, std::string> clang_types;
};
class Range {
public:
Range(std::pair<clang::Offset, clang::Offset> offsets, int kind):
offsets(offsets), kind(kind) {}
std::pair<clang::Offset, clang::Offset> offsets;
int kind;
};
class AutoCompleteData {
public:
explicit AutoCompleteData(const std::vector<clang::CompletionChunk> &chunks) :
chunks(chunks) { }
std::vector<clang::CompletionChunk> chunks;
std::string brief_comments;
std::unordered_map<std::string, DocumentationSearch> documentation_searches;
};
class Token {
@ -71,9 +56,32 @@ namespace Source {
std::string usr;
};
class Offset {
public:
Offset() {}
Offset(unsigned line, unsigned index): line(line), index(index) {}
bool operator==(const Offset &o) {return (line==o.line && index==o.index);}
unsigned line;
unsigned index;
};
class FixIt {
public:
enum class Type {INSERT, REPLACE, ERASE};
FixIt(const std::string &source, const std::pair<Offset, Offset> &offsets);
std::string string(Glib::RefPtr<Gtk::TextBuffer> buffer);
Type type;
std::string source;
std::pair<Offset, Offset> offsets;
};
class View : public Gsv::View {
public:
View(const boost::filesystem::path &file_path, Glib::RefPtr<Gsv::Language> language);
View(const boost::filesystem::path &file_path, const boost::filesystem::path &project_path, Glib::RefPtr<Gsv::Language> language);
~View();
virtual void configure();
@ -89,12 +97,16 @@ namespace Source {
void paste();
boost::filesystem::path file_path;
boost::filesystem::path project_path;
Glib::RefPtr<Gsv::Language> language;
std::function<std::pair<std::string, clang::Offset>()> get_declaration_location;
std::function<std::pair<std::string, Offset>()> get_declaration_location;
std::function<void()> goto_method;
std::function<Token()> get_token;
std::function<std::vector<std::string>()> get_token_data;
std::function<size_t(const Token &token, const std::string &text)> rename_similar_tokens;
std::function<void()> goto_next_diagnostic;
std::function<void()> apply_fix_its;
std::function<void(View* view, const std::string &status)> on_update_status;
std::function<void(View* view, const std::string &info)> on_update_info;
@ -106,6 +118,9 @@ namespace Source {
void spellcheck();
void remove_spellcheck_errors();
void goto_next_spellcheck_error();
void set_tab_char_and_size(char tab_char, unsigned tab_size);
std::pair<char, unsigned> get_tab_char_and_size() {return {tab_char, tab_size};}
protected:
bool source_readable;
Tooltips diagnostic_tooltips;
@ -124,6 +139,10 @@ namespace Source {
std::string get_line_before(const Gtk::TextIter &iter);
std::string get_line_before(Glib::RefPtr<Gtk::TextBuffer::Mark> mark);
std::string get_line_before();
Gtk::TextIter get_tabs_end_iter(const Gtk::TextIter &iter);
Gtk::TextIter get_tabs_end_iter(Glib::RefPtr<Gtk::TextBuffer::Mark> mark);
Gtk::TextIter get_tabs_end_iter(int line_nr);
Gtk::TextIter get_tabs_end_iter();
bool find_start_of_closed_expression(Gtk::TextIter iter, Gtk::TextIter &found_iter);
bool find_open_expression_symbol(Gtk::TextIter iter, const Gtk::TextIter &until_iter, Gtk::TextIter &found_iter);
@ -137,7 +156,6 @@ namespace Source {
unsigned tab_size;
char tab_char;
std::string tab;
std::regex tabs_regex;
bool spellcheck_all=false;
std::unique_ptr<SelectionDialog> spellcheck_suggestions_dialog;
@ -169,106 +187,9 @@ namespace Source {
static Glib::RefPtr<CompletionBuffer> create() {return Glib::RefPtr<CompletionBuffer>(new CompletionBuffer());}
};
public:
GenericView(const boost::filesystem::path &file_path, Glib::RefPtr<Gsv::Language> language);
GenericView(const boost::filesystem::path &file_path, const boost::filesystem::path &project_path, Glib::RefPtr<Gsv::Language> language);
void parse_language_file(Glib::RefPtr<CompletionBuffer> &completion_buffer, bool &has_context_class, const boost::property_tree::ptree &pt);
};
class ClangViewParse : public View {
public:
ClangViewParse(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path, Glib::RefPtr<Gsv::Language> language);
~ClangViewParse();
void configure();
boost::filesystem::path project_path;
void start_reparse();
bool reparse_needed=false;
protected:
void init_parse();
bool on_key_press_event(GdkEventKey* key);
std::unique_ptr<clang::TranslationUnit> clang_tu;
std::mutex parsing_mutex;
std::unique_ptr<clang::Tokens> clang_tokens;
sigc::connection delayed_reparse_connection;
std::shared_ptr<Terminal::InProgress> parsing_in_progress;
std::thread parse_thread;
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);
std::regex bracket_regex;
std::regex no_bracket_statement_regex;
std::regex no_bracket_no_para_statement_regex;
std::set<int> diagnostic_offsets;
private:
std::map<std::string, std::string> get_buffer_map() const;
void update_syntax();
std::set<std::string> last_syntax_tags;
void update_diagnostics();
static clang::Index clang_index;
std::vector<std::string> get_compilation_commands();
Glib::Dispatcher parse_done;
Glib::Dispatcher parse_start;
Glib::Dispatcher parse_fail;
std::map<std::string, std::string> parse_thread_buffer_map;
std::mutex parse_thread_buffer_map_mutex;
std::atomic<bool> parse_thread_go;
std::atomic<bool> parse_thread_mapped;
};
class ClangViewAutocomplete : public ClangViewParse {
public:
ClangViewAutocomplete(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path, Glib::RefPtr<Gsv::Language> language);
void async_delete();
bool restart_parse();
protected:
bool on_key_press_event(GdkEventKey* key);
std::thread autocomplete_thread;
private:
void start_autocomplete();
void autocomplete();
std::unique_ptr<CompletionDialog> completion_dialog;
bool completion_dialog_shown=false;
std::vector<Source::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;
bool autocomplete_starting=false;
std::atomic<bool> autocomplete_cancel_starting;
guint last_keyval=0;
std::string prefix;
std::mutex prefix_mutex;
Glib::Dispatcher do_delete_object;
Glib::Dispatcher do_restart_parse;
std::thread delete_thread;
std::thread restart_parse_thread;
bool restart_parse_running=false;
};
class ClangViewRefactor : public ClangViewAutocomplete {
public:
ClangViewRefactor(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path, Glib::RefPtr<Gsv::Language> language);
~ClangViewRefactor();
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;
};
class ClangView : public ClangViewRefactor {
public:
ClangView(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path, Glib::RefPtr<Gsv::Language> language);
};
}; // class Source
}
#endif // JUCI_SOURCE_H_

1236
src/source_clang.cc

File diff suppressed because it is too large Load Diff

128
src/source_clang.h

@ -0,0 +1,128 @@
#ifndef JUCI_SOURCE_CLANG_H_
#define JUCI_SOURCE_CLANG_H_
#include <thread>
#include <atomic>
#include <mutex>
#include <set>
#include <regex>
#include "clangmm.h"
#include "source.h"
namespace Source {
class ClangViewParse : public View {
public:
class TokenRange {
public:
TokenRange(std::pair<clang::Offset, clang::Offset> offsets, int kind):
offsets(offsets), kind(kind) {}
std::pair<clang::Offset, clang::Offset> offsets;
int kind;
};
ClangViewParse(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path, Glib::RefPtr<Gsv::Language> language);
~ClangViewParse();
void configure();
void start_reparse();
bool reparse_needed=false;
protected:
void init_parse();
bool on_key_press_event(GdkEventKey* key);
std::unique_ptr<clang::TranslationUnit> clang_tu;
std::mutex parsing_mutex;
std::unique_ptr<clang::Tokens> clang_tokens;
sigc::connection delayed_reparse_connection;
std::shared_ptr<Terminal::InProgress> parsing_in_progress;
std::thread parse_thread;
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);
std::regex bracket_regex;
std::regex no_bracket_statement_regex;
std::regex no_bracket_no_para_statement_regex;
std::set<int> diagnostic_offsets;
std::vector<FixIt> fix_its;
private:
std::map<std::string, std::string> get_buffer_map() const;
void update_syntax();
std::set<std::string> last_syntax_tags;
void update_diagnostics();
static clang::Index clang_index;
std::vector<std::string> get_compilation_commands();
Glib::Dispatcher parse_done;
Glib::Dispatcher parse_start;
Glib::Dispatcher parse_fail;
std::map<std::string, std::string> parse_thread_buffer_map;
std::mutex parse_thread_buffer_map_mutex;
std::atomic<bool> parse_thread_go;
std::atomic<bool> parse_thread_mapped;
};
class ClangViewAutocomplete : public ClangViewParse {
public:
class AutoCompleteData {
public:
explicit AutoCompleteData(const std::vector<clang::CompletionChunk> &chunks) :
chunks(chunks) { }
std::vector<clang::CompletionChunk> chunks;
std::string brief_comments;
};
ClangViewAutocomplete(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path, Glib::RefPtr<Gsv::Language> language);
void async_delete();
bool restart_parse();
protected:
bool on_key_press_event(GdkEventKey* key);
std::thread autocomplete_thread;
private:
void start_autocomplete();
void autocomplete();
std::unique_ptr<CompletionDialog> completion_dialog;
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;
std::string prefix;
std::mutex prefix_mutex;
Glib::Dispatcher do_delete_object;
Glib::Dispatcher do_restart_parse;
std::thread delete_thread;
std::thread restart_parse_thread;
bool restart_parse_running=false;
};
class ClangViewRefactor : public ClangViewAutocomplete {
public:
ClangViewRefactor(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path, Glib::RefPtr<Gsv::Language> language);
~ClangViewRefactor();
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;
};
class ClangView : public ClangViewRefactor {
public:
ClangView(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path, Glib::RefPtr<Gsv::Language> language);
};
}
#endif // JUCI_SOURCE_CLANG_H_

141
src/window.cc

@ -117,6 +117,12 @@ Window::Window() : box(Gtk::ORIENTATION_VERTICAL), compiling(false) {
if(auto menu_item=dynamic_cast<Gtk::MenuItem*>(menu.ui_manager->get_widget("/MenuBar/SourceMenu/SourceGotoNextDiagnostic")))
menu_item->set_sensitive((bool)notebook.get_current_view()->goto_next_diagnostic);
if(auto menu_item=dynamic_cast<Gtk::MenuItem*>(menu.ui_manager->get_widget("/MenuBar/SourceMenu/SourceApplyFixIts")))
menu_item->set_sensitive((bool)notebook.get_current_view()->apply_fix_its);
if(auto menu_item=dynamic_cast<Gtk::MenuItem*>(menu.ui_manager->get_widget("/MenuBar/SourceMenu/SourceFindDocumentation")))
menu_item->set_sensitive((bool)notebook.get_current_view()->get_token_data);
Singleton::directories()->select(notebook.get_current_view()->file_path);
if(auto source_view=dynamic_cast<Source::ClangView*>(notebook.get_current_view())) {
@ -327,6 +333,13 @@ void Window::create_menu() {
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]() {
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.action_group->add(Gtk::Action::create("SourceGotoLine", "Go to Line"), Gtk::AccelKey(menu.key_map["source_goto_line"]), [this]() {
goto_line_entry();
});
@ -363,6 +376,46 @@ void Window::create_menu() {
menu.action_group->add(Gtk::Action::create("SourceRename", "Rename"), Gtk::AccelKey(menu.key_map["source_rename"]), [this]() {
rename_token_entry();
});
menu.action_group->add(Gtk::Action::create("SourceFindDocumentation", "Find Documentation"), Gtk::AccelKey(menu.key_map["source_find_documentation"]), [this]() {
if(notebook.get_current_page()!=-1) {
if(notebook.get_current_view()->get_token_data) {
auto data=notebook.get_current_view()->get_token_data();
if(data.size()>0) {
auto documentation_search=Singleton::Config::source()->documentation_searches.find(data[0]);
if(documentation_search!=Singleton::Config::source()->documentation_searches.end()) {
std::string token_query;
for(size_t c=1;c<data.size();c++) {
if(data[c].size()>0) {
if(token_query.size()>0)
token_query+=documentation_search->second.separator;
token_query+=data[c];
}
}
if(token_query.size()>0) {
std::unordered_map<std::string, std::string>::iterator query;
if(data[1].size()>0)
query=documentation_search->second.queries.find(data[1]);
else
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__
Singleton::terminal()->execute("open \""+uri+"\"");
#else
GError* error=NULL;
gtk_show_uri(NULL, uri.c_str(), GDK_CURRENT_TIME, &error);
g_clear_error(&error);
#endif
}
}
}
}
}
}
});
menu.action_group->add(Gtk::Action::create("SourceGotoNextDiagnostic", "Go to next Diagnostic"), Gtk::AccelKey(menu.key_map["source_goto_next_diagnostic"]), [this]() {
if(notebook.get_current_page()!=-1) {
if(notebook.get_current_view()->goto_next_diagnostic) {
@ -370,6 +423,13 @@ void Window::create_menu() {
}
}
});
menu.action_group->add(Gtk::Action::create("SourceApplyFixIts", "Apply Fix-Its"), Gtk::AccelKey(menu.key_map["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();
}
}
});
menu.action_group->add(Gtk::Action::create("ProjectCompileAndRun", "Compile and Run"), Gtk::AccelKey(menu.key_map["compile_and_run"]), [this]() {
if(notebook.get_current_page()==-1 || compiling)
@ -425,12 +485,28 @@ void Window::create_menu() {
});
menu.action_group->add(Gtk::Action::create("ProjectRunCommand", "Run Command"), Gtk::AccelKey(menu.key_map["run_command"]), [this]() {
entry_box.clear();
entry_box.labels.emplace_back();
auto label_it=entry_box.labels.begin();
label_it->update=[label_it](int state, const std::string& message){
label_it->set_text("Run Command directory order: file project path, file directory, opened directory, current directory");
};
label_it->update(0, "");
entry_box.entries.emplace_back(last_run_command, [this](const std::string& content){
if(content!="") {
last_run_command=content;
boost::filesystem::path run_path;
if(notebook.get_current_page()!=-1) {
if(notebook.get_current_view()->project_path!="")
run_path=notebook.get_current_view()->project_path;
else
run_path=notebook.get_current_view()->file_path.parent_path();
}
else
run_path=Singleton::directories()->current_path;
Singleton::terminal()->async_print("Running: "+content+'\n');
Singleton::terminal()->async_execute(content, Singleton::directories()->current_path, [this, content](int exit_code) {
Singleton::terminal()->async_print(content + " returned: " + std::to_string(exit_code)+'\n');
Singleton::terminal()->async_execute(content, run_path, [this, content](int exit_code){
Singleton::terminal()->async_print(content+" returned: "+std::to_string(exit_code)+'\n');
});
}
entry_box.hide();
@ -617,6 +693,65 @@ void Window::search_and_replace_entry() {
entry_box.show();
}
void Window::set_tab_entry() {
entry_box.clear();
if(notebook.get_current_page()!=-1) {
auto tab_char_and_size=notebook.get_current_view()->get_tab_char_and_size();
entry_box.labels.emplace_back();
auto label_it=entry_box.labels.begin();
entry_box.entries.emplace_back(std::to_string(tab_char_and_size.second));
auto entry_tab_size_it=entry_box.entries.begin();
entry_tab_size_it->set_placeholder_text("Tab size");
char tab_char=tab_char_and_size.first;
std::string tab_char_string;
if(tab_char==' ')
tab_char_string="space";
else if(tab_char=='\t')
tab_char_string="tab";
entry_box.entries.emplace_back(tab_char_string);
auto entry_tab_char_it=entry_box.entries.rbegin();
entry_tab_char_it->set_placeholder_text("Tab char");
const auto activate_function=[this, entry_tab_char_it, entry_tab_size_it, label_it](const std::string& content){
if(notebook.get_current_page()!=-1) {
char tab_char=0;
unsigned tab_size=0;
try {
tab_size = static_cast<unsigned>(stoul(entry_tab_size_it->get_text()));
std::string tab_char_string=entry_tab_char_it->get_text();
std::transform(tab_char_string.begin(), tab_char_string.end(), tab_char_string.begin(), ::tolower);
if(tab_char_string=="space")
tab_char=' ';
else if(tab_char_string=="tab")
tab_char='\t';
}
catch(const std::exception &e) {}
if(tab_char!=0 && tab_size>0) {
notebook.get_current_view()->set_tab_char_and_size(tab_char, tab_size);
entry_box.hide();
}
else {
label_it->set_text("Tab size must be >0 and tab char set to either 'space' or 'tab'");
}
}
};
entry_tab_char_it->on_activate=activate_function;
entry_tab_size_it->on_activate=activate_function;
entry_box.buttons.emplace_back("Set tab in current buffer", [this, entry_tab_char_it](){
entry_tab_char_it->activate();
});
entry_box.show();
}
}
void Window::goto_line_entry() {
entry_box.clear();
if(notebook.get_current_page()!=-1) {
@ -656,7 +791,7 @@ void Window::rename_token_entry() {
entry_box.labels.emplace_back();
auto label_it=entry_box.labels.begin();
label_it->update=[label_it](int state, const std::string& message){
label_it->set_text("Warning: only opened and parsed tabs will have its content renamed, and modified files will be saved.");
label_it->set_text("Warning: only opened and parsed tabs will have its content renamed, and modified files will be saved");
};
label_it->update(0, "");
entry_box.entries.emplace_back(token->spelling, [this, token](const std::string& content){

2
src/window.h

@ -6,7 +6,6 @@
#include "entrybox.h"
#include "notebook.h"
#include "menu.h"
#include <boost/property_tree/json_parser.hpp>
#include <atomic>
class Window : public Gtk::Window {
@ -43,6 +42,7 @@ private:
void create_menu();
void hide();
void search_and_replace_entry();
void set_tab_entry();
void goto_line_entry();
void rename_token_entry();
void generate_keybindings();

Loading…
Cancel
Save