Browse Source

Added fix its, and some minor cleanup.

merge-requests/365/head
eidheim 10 years ago
parent
commit
b37a9d38d5
  1. 3
      src/files.h
  2. 1
      src/menu.cc
  3. 135
      src/source.cc
  4. 61
      src/source.h
  5. 10
      src/window.cc

3
src/files.h

@ -1,6 +1,6 @@
#include <string> #include <string>
#define JUCI_VERSION "0.9.2" #define JUCI_VERSION "0.9.3"
const std::string configjson = const std::string configjson =
"{\n" "{\n"
@ -74,6 +74,7 @@ const std::string configjson =
" \"source_goto_method\": \"<primary>m\",\n" " \"source_goto_method\": \"<primary>m\",\n"
" \"source_rename\": \"<primary>r\",\n" " \"source_rename\": \"<primary>r\",\n"
" \"source_goto_next_diagnostic\": \"<primary>e\",\n" " \"source_goto_next_diagnostic\": \"<primary>e\",\n"
" \"source_apply_fix_its\": \"<alt>space\",\n"
" \"compile_and_run\": \"<primary>Return\",\n" " \"compile_and_run\": \"<primary>Return\",\n"
" \"compile\": \"<primary><shift>Return\",\n" " \"compile\": \"<primary><shift>Return\",\n"
" \"run_command\": \"<alt>Return\",\n" " \"run_command\": \"<alt>Return\",\n"

1
src/menu.cc

@ -59,6 +59,7 @@ Menu::Menu() {
" <menuitem action=\"SourceRename\"/>\n" " <menuitem action=\"SourceRename\"/>\n"
" <separator/>\n" " <separator/>\n"
" <menuitem action=\"SourceGotoNextDiagnostic\"/>\n" " <menuitem action=\"SourceGotoNextDiagnostic\"/>\n"
" <menuitem action=\"SourceApplyFixIts\"/>\n"
" <separator/>\n" " <separator/>\n"
" </menu>\n" " </menu>\n"
" <menu action=\"ProjectMenu\">\n" " <menu action=\"ProjectMenu\">\n"

135
src/source.cc

@ -42,6 +42,38 @@ Glib::RefPtr<Gsv::Language> Source::guess_language(const boost::filesystem::path
return language; return language;
} }
Source::FixIt::FixIt(const std::string &source, const std::pair<Offset, Offset> &offsets) : source(source), offsets(offsets) {
if(source.size()==0)
type=Type::ERASE;
else {
if(this->offsets.first==this->offsets.second)
type=Type::INSERT;
else
type=Type::REPLACE;
}
}
std::string Source::FixIt::string() {
std::string text;
if(type==Type::INSERT) {
text+="Insert "+source+" at ";
text+=std::to_string(offsets.first.line)+":"+std::to_string(offsets.first.offset);
}
else if(type==Type::REPLACE) {
text+="Replace ";
text+=std::to_string(offsets.first.line)+":"+std::to_string(offsets.first.offset)+" - ";
text+=std::to_string(offsets.second.line)+":"+std::to_string(offsets.second.offset);
text+=" with "+source;
}
else {
text+="Erase ";
text+=std::to_string(offsets.first.line)+":"+std::to_string(offsets.first.offset)+" - ";
text+=std::to_string(offsets.second.line)+":"+std::to_string(offsets.second.offset);
}
return text;
}
////////////// //////////////
//// View //// //// View ////
////////////// //////////////
@ -1504,7 +1536,7 @@ std::vector<std::string> Source::ClangViewParse::get_compilation_commands() {
} }
void Source::ClangViewParse::update_syntax() { void Source::ClangViewParse::update_syntax() {
std::vector<Source::Range> ranges; std::vector<TokenRange> ranges;
for (auto &token : *clang_tokens) { for (auto &token : *clang_tokens) {
//if(token.get_kind()==0) // PunctuationToken //if(token.get_kind()==0) // PunctuationToken
//ranges.emplace_back(token.offsets, (int) token.get_cursor().get_kind()); //ranges.emplace_back(token.offsets, (int) token.get_cursor().get_kind());
@ -1544,11 +1576,13 @@ void Source::ClangViewParse::update_syntax() {
void Source::ClangViewParse::update_diagnostics() { void Source::ClangViewParse::update_diagnostics() {
diagnostic_offsets.clear(); diagnostic_offsets.clear();
diagnostic_tooltips.clear(); diagnostic_tooltips.clear();
fix_its.clear();
get_buffer()->remove_tag_by_name("def:warning_underline", get_buffer()->begin(), get_buffer()->end()); get_buffer()->remove_tag_by_name("def:warning_underline", get_buffer()->begin(), get_buffer()->end());
get_buffer()->remove_tag_by_name("def:error_underline", get_buffer()->begin(), get_buffer()->end()); get_buffer()->remove_tag_by_name("def:error_underline", get_buffer()->begin(), get_buffer()->end());
auto diagnostics=clang_tu->get_diagnostics(); auto diagnostics=clang_tu->get_diagnostics();
size_t warnings=0; size_t num_warnings=0;
size_t errors=0; size_t num_errors=0;
size_t num_fix_its=0;
for(auto &diagnostic: diagnostics) { for(auto &diagnostic: diagnostics) {
if(diagnostic.path==file_path.string()) { if(diagnostic.path==file_path.string()) {
auto start_line=get_line(diagnostic.offsets.first.line-1); //index is sometimes off the line auto start_line=get_line(diagnostic.offsets.first.line-1); //index is sometimes off the line
@ -1573,19 +1607,50 @@ void Source::ClangViewParse::update_diagnostics() {
std::string diagnostic_tag_name; std::string diagnostic_tag_name;
if(diagnostic.severity<=CXDiagnostic_Warning) { if(diagnostic.severity<=CXDiagnostic_Warning) {
diagnostic_tag_name="def:warning"; diagnostic_tag_name="def:warning";
warnings++; num_warnings++;
} }
else { else {
diagnostic_tag_name="def:error"; diagnostic_tag_name="def:error";
errors++; num_errors++;
} }
auto spelling=diagnostic.spelling; auto spelling=diagnostic.spelling;
auto severity_spelling=diagnostic.severity_spelling; auto severity_spelling=diagnostic.severity_spelling;
auto create_tooltip_buffer=[this, spelling, severity_spelling, diagnostic_tag_name]() {
std::string fix_its_string;
unsigned fix_its_count=0;
for(auto &fix_it: diagnostic.fix_its) {
//Convert line index to line offset for correct output:
auto clang_offsets=fix_it.offsets;
std::pair<FixIt::Offset, FixIt::Offset> offsets;
offsets.first.line=clang_offsets.first.line;
offsets.second.line=clang_offsets.second.line;
auto iter=get_buffer()->get_iter_at_line_index(clang_offsets.first.line-1, clang_offsets.first.index-1);
offsets.first.offset=iter.get_line_offset()+1;
iter=get_buffer()->get_iter_at_line_index(clang_offsets.second.line-1, clang_offsets.second.index-1);
offsets.second.offset=iter.get_line_offset()+1;
fix_its.emplace_back(fix_it.source, offsets);
if(fix_its_string.size()>0)
fix_its_string+='\n';
fix_its_string+=fix_its.back().string();
fix_its_count++;
num_fix_its++;
}
if(fix_its_count==1)
fix_its_string.insert(0, "Fix-it:\n");
else if(fix_its_count>1)
fix_its_string.insert(0, "Fix-its:\n");
auto create_tooltip_buffer=[this, spelling, severity_spelling, diagnostic_tag_name, fix_its_string]() {
auto tooltip_buffer=Gtk::TextBuffer::create(get_buffer()->get_tag_table()); auto tooltip_buffer=Gtk::TextBuffer::create(get_buffer()->get_tag_table());
tooltip_buffer->insert_with_tag(tooltip_buffer->get_insert()->get_iter(), severity_spelling, diagnostic_tag_name); tooltip_buffer->insert_with_tag(tooltip_buffer->get_insert()->get_iter(), severity_spelling, diagnostic_tag_name);
tooltip_buffer->insert_with_tag(tooltip_buffer->get_insert()->get_iter(), ":\n"+spelling, "def:note"); tooltip_buffer->insert_with_tag(tooltip_buffer->get_insert()->get_iter(), ":\n"+spelling, "def:note");
if(fix_its_string.size()>0) {
tooltip_buffer->insert_with_tag(tooltip_buffer->get_insert()->get_iter(), ":\n\n"+fix_its_string, "def:note");
}
return tooltip_buffer; return tooltip_buffer;
}; };
diagnostic_tooltips.emplace_back(create_tooltip_buffer, *this, get_buffer()->create_mark(start), get_buffer()->create_mark(end)); diagnostic_tooltips.emplace_back(create_tooltip_buffer, *this, get_buffer()->create_mark(start), get_buffer()->create_mark(end));
@ -1600,16 +1665,23 @@ void Source::ClangViewParse::update_diagnostics() {
} }
} }
std::string diagnostic_info; std::string diagnostic_info;
if(warnings>0) { if(num_warnings>0) {
diagnostic_info+=std::to_string(warnings)+" warning"; diagnostic_info+=std::to_string(num_warnings)+" warning";
if(warnings>1) if(num_warnings>1)
diagnostic_info+='s';
}
if(num_errors>0) {
if(num_warnings>0)
diagnostic_info+=", ";
diagnostic_info+=std::to_string(num_errors)+" error";
if(num_errors>1)
diagnostic_info+='s'; diagnostic_info+='s';
} }
if(errors>0) { if(num_fix_its>0) {
if(warnings>0) if(num_warnings>0 || num_errors>0)
diagnostic_info+=", "; diagnostic_info+=", ";
diagnostic_info+=std::to_string(errors)+" error"; diagnostic_info+=std::to_string(num_fix_its)+" fix it";
if(errors>1) if(num_fix_its>1)
diagnostic_info+='s'; diagnostic_info+='s';
} }
set_info(" "+diagnostic_info); set_info(" "+diagnostic_info);
@ -1966,7 +2038,7 @@ void Source::ClangViewAutocomplete::autocomplete() {
if(!autocomplete_starting) { if(!autocomplete_starting) {
autocomplete_starting=true; autocomplete_starting=true;
autocomplete_cancel_starting=false; autocomplete_cancel_starting=false;
std::shared_ptr<std::vector<Source::AutoCompleteData> > ac_data=std::make_shared<std::vector<Source::AutoCompleteData> >(); std::shared_ptr<std::vector<AutoCompleteData> > ac_data=std::make_shared<std::vector<AutoCompleteData> >();
autocomplete_done_connection.disconnect(); autocomplete_done_connection.disconnect();
autocomplete_done_connection=autocomplete_done.connect([this, ac_data](){ autocomplete_done_connection=autocomplete_done.connect([this, ac_data](){
autocomplete_starting=false; autocomplete_starting=false;
@ -2076,8 +2148,8 @@ void Source::ClangViewAutocomplete::autocomplete() {
} }
} }
std::vector<Source::AutoCompleteData> Source::ClangViewAutocomplete::get_autocomplete_suggestions(int line_number, int column, std::map<std::string, std::string>& buffer_map) { std::vector<Source::ClangViewAutocomplete::AutoCompleteData> Source::ClangViewAutocomplete::get_autocomplete_suggestions(int line_number, int column, std::map<std::string, std::string>& buffer_map) {
std::vector<Source::AutoCompleteData> suggestions; std::vector<AutoCompleteData> suggestions;
auto results=clang_tu->get_code_completions(buffer_map, line_number, column); auto results=clang_tu->get_code_completions(buffer_map, line_number, column);
if(results.cx_results==NULL) { if(results.cx_results==NULL) {
parse_thread_stop=true; parse_thread_stop=true;
@ -2290,6 +2362,37 @@ Source::ClangViewAutocomplete(file_path, project_path, language) {
} }
} }
}; };
apply_fix_its=[this]() {
std::vector<std::pair<Glib::RefPtr<Gtk::TextMark>, Glib::RefPtr<Gtk::TextMark> > > fix_it_marks;
if(source_readable) {
for(auto &fix_it: fix_its) {
auto start_iter=get_buffer()->get_iter_at_line_offset(fix_it.offsets.first.line-1, fix_it.offsets.first.offset-1);
auto end_iter=get_buffer()->get_iter_at_line_offset(fix_it.offsets.second.line-1, fix_it.offsets.second.offset-1);
fix_it_marks.emplace_back(get_buffer()->create_mark(start_iter), get_buffer()->create_mark(end_iter));
}
size_t c=0;
get_source_buffer()->begin_user_action();
for(auto &fix_it: fix_its) {
if(fix_it.type==FixIt::Type::INSERT) {
get_buffer()->insert(fix_it_marks[c].first->get_iter(), fix_it.source);
}
if(fix_it.type==FixIt::Type::REPLACE) {
get_buffer()->erase(fix_it_marks[c].first->get_iter(), fix_it_marks[c].second->get_iter());
get_buffer()->insert(fix_it_marks[c].first->get_iter(), fix_it.source);
}
if(fix_it.type==FixIt::Type::ERASE) {
get_buffer()->erase(fix_it_marks[c].first->get_iter(), fix_it_marks[c].second->get_iter());
}
c++;
}
for(auto &mark_pair: fix_it_marks) {
get_buffer()->delete_mark(mark_pair.first);
get_buffer()->delete_mark(mark_pair.second);
}
get_source_buffer()->end_user_action();
}
};
} }
void Source::ClangViewRefactor::tag_similar_tokens(const Token &token) { void Source::ClangViewRefactor::tag_similar_tokens(const Token &token) {

61
src/source.h

@ -38,22 +38,6 @@ namespace Source {
bool show_line_numbers; bool show_line_numbers;
std::unordered_map<std::string, std::string> clang_types; std::unordered_map<std::string, std::string> clang_types;
}; };
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;
};
class Token { class Token {
public: public:
@ -70,6 +54,31 @@ namespace Source {
std::string spelling; std::string spelling;
std::string usr; std::string usr;
}; };
class FixIt {
public:
class Offset {
public:
Offset() {}
Offset(unsigned line, unsigned offset): line(line), offset(offset) {}
bool operator==(const Offset &o) {return (line==o.line && offset==o.offset);}
unsigned line;
unsigned offset;
};
enum class Type {INSERT, REPLACE, ERASE};
FixIt(Type type, const std::string &source, const std::pair<Offset, Offset> &offsets):
type(type), source(source), offsets(offsets) {}
FixIt(const std::string &source, const std::pair<Offset, Offset> &offsets);
std::string string();
Type type;
std::string source;
std::pair<Offset, Offset> offsets;
};
class View : public Gsv::View { class View : public Gsv::View {
public: public:
@ -95,6 +104,7 @@ namespace Source {
std::function<Token()> get_token; std::function<Token()> get_token;
std::function<size_t(const Token &token, const std::string &text)> rename_similar_tokens; std::function<size_t(const Token &token, const std::string &text)> rename_similar_tokens;
std::function<void()> goto_next_diagnostic; 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 &status)> on_update_status;
std::function<void(View* view, const std::string &info)> on_update_info; std::function<void(View* view, const std::string &info)> on_update_info;
@ -176,6 +186,14 @@ namespace Source {
class ClangViewParse : public View { class ClangViewParse : public View {
public: 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(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path, Glib::RefPtr<Gsv::Language> language);
~ClangViewParse(); ~ClangViewParse();
void configure(); void configure();
@ -204,6 +222,7 @@ namespace Source {
std::regex no_bracket_no_para_statement_regex; std::regex no_bracket_no_para_statement_regex;
std::set<int> diagnostic_offsets; std::set<int> diagnostic_offsets;
std::vector<FixIt> fix_its;
private: private:
std::map<std::string, std::string> get_buffer_map() const; std::map<std::string, std::string> get_buffer_map() const;
void update_syntax(); void update_syntax();
@ -224,6 +243,14 @@ namespace Source {
class ClangViewAutocomplete : public ClangViewParse { class ClangViewAutocomplete : public ClangViewParse {
public: 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); ClangViewAutocomplete(const boost::filesystem::path &file_path, const boost::filesystem::path& project_path, Glib::RefPtr<Gsv::Language> language);
void async_delete(); void async_delete();
bool restart_parse(); bool restart_parse();
@ -235,7 +262,7 @@ namespace Source {
void autocomplete(); void autocomplete();
std::unique_ptr<CompletionDialog> completion_dialog; std::unique_ptr<CompletionDialog> completion_dialog;
bool completion_dialog_shown=false; 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); std::vector<AutoCompleteData> get_autocomplete_suggestions(int line_number, int column, std::map<std::string, std::string>& buffer_map);
Glib::Dispatcher autocomplete_done; Glib::Dispatcher autocomplete_done;
sigc::connection autocomplete_done_connection; sigc::connection autocomplete_done_connection;
Glib::Dispatcher autocomplete_fail; Glib::Dispatcher autocomplete_fail;

10
src/window.cc

@ -115,6 +115,9 @@ Window::Window() : box(Gtk::ORIENTATION_VERTICAL), notebook(directories), compil
if(auto menu_item=dynamic_cast<Gtk::MenuItem*>(menu.ui_manager->get_widget("/MenuBar/SourceMenu/SourceGotoNextDiagnostic"))) 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); 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);
directories.select(notebook.get_current_view()->file_path); directories.select(notebook.get_current_view()->file_path);
@ -300,6 +303,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]() { 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) if(notebook.get_current_page()==-1 || compiling)

Loading…
Cancel
Save