Browse Source

Made use of boost::optional, and some other cleanup

pipelines/235045657
eidheim 6 years ago
parent
commit
b2c4056be8
  1. 7
      src/cmake.cpp
  2. 10
      src/documentation.cpp
  3. 5
      src/git.cpp
  4. 3
      src/git.hpp
  5. 1
      src/grep.cpp
  6. 5
      src/meson.cpp
  7. 92
      src/notebook.cpp
  8. 10
      src/notebook.hpp
  9. 6
      src/selection_dialog.cpp
  10. 3
      src/selection_dialog.hpp
  11. 31
      src/source.cpp
  12. 2
      src/source.hpp
  13. 30
      src/source_base.cpp
  14. 7
      src/source_base.hpp
  15. 23
      src/source_language_protocol.cpp
  16. 3
      src/source_language_protocol.hpp
  17. 50
      src/terminal.cpp
  18. 8
      src/terminal.hpp
  19. 14
      src/tooltips.cpp
  20. 5
      src/tooltips.hpp
  21. 41
      tests/terminal_test.cpp

7
src/cmake.cpp

@ -5,6 +5,7 @@
#include "filesystem.hpp"
#include "terminal.hpp"
#include "utility.hpp"
#include <boost/optional.hpp>
#include <regex>
CMake::CMake(const boost::filesystem::path &path) {
@ -141,7 +142,7 @@ boost::filesystem::path CMake::get_executable(const boost::filesystem::path &bui
}
}
size_t best_match_size = -1;
boost::optional<size_t> best_match_size;
boost::filesystem::path best_match_executable;
for(auto &cmake_executable : cmake_executables) {
@ -154,7 +155,7 @@ boost::filesystem::path CMake::get_executable(const boost::filesystem::path &bui
auto command_file_directory = command_file.parent_path();
if(filesystem::file_in_path(file_path, command_file_directory)) {
auto size = static_cast<size_t>(std::distance(command_file_directory.begin(), command_file_directory.end()));
if(best_match_size == static_cast<size_t>(-1) || best_match_size < size) {
if(best_match_size < size) {
best_match_size = size;
best_match_executable = maybe_executable;
}
@ -173,7 +174,7 @@ boost::filesystem::path CMake::get_executable(const boost::filesystem::path &bui
auto command_file_directory = command_file.parent_path();
if(filesystem::file_in_path(file_path, command_file_directory)) {
auto size = static_cast<size_t>(std::distance(command_file_directory.begin(), command_file_directory.end()));
if(best_match_size == static_cast<size_t>(-1) || best_match_size < size) {
if(!best_match_size || best_match_size < size) {
best_match_size = size;
best_match_executable = maybe_executable;
}

10
src/documentation.cpp

@ -1,6 +1,10 @@
#include "documentation.hpp"
#include <unordered_map>
// For both get_headers and get_url:
// - Removed " (utility)" from "std::move (utility)"
// - Removed lines with "move (algorithm)"
std::vector<std::string> Documentation::CppReference::get_headers(const std::string &symbol) noexcept {
// Extracted from http://upload.cppreference.com/mwiki/images/b/b1/cppreference-doc-20190607.zip
// Using raw string instead of map to reduce compile time
@ -1908,7 +1912,7 @@ std::ignore tuple
std::ranges::swap concepts
std::forward utility
std::exchange utility
std::move (utility) utility
std::move utility
std::move_if_noexcept utility
std::declval utility
std::as_const utility
@ -2342,7 +2346,6 @@ std::copy algorithm
std::copy_if algorithm
std::copy_n algorithm
std::copy_backward algorithm
std::move (algorithm) algorithm
std::move_backward algorithm
std::fill algorithm
std::fill_n algorithm
@ -5939,7 +5942,7 @@ std::ignore cpp/utility/tuple/ignore
std::ranges::swap cpp/utility/ranges/swap
std::forward cpp/utility/forward
std::exchange cpp/utility/exchange
std::move (utility) cpp/utility/move
std::move cpp/utility/move
std::move_if_noexcept cpp/utility/move_if_noexcept
std::declval cpp/utility/declval
std::as_const cpp/utility/as_const
@ -9073,7 +9076,6 @@ std::copy cpp/algorithm/copy
std::copy_if cpp/algorithm/copy
std::copy_n cpp/algorithm/copy_n
std::copy_backward cpp/algorithm/copy_backward
std::move (algorithm) cpp/algorithm/move
std::move_backward cpp/algorithm/move_backward
std::fill cpp/algorithm/fill
std::fill_n cpp/algorithm/fill_n

5
src/git.cpp

@ -252,11 +252,10 @@ std::shared_ptr<Git::Repository> Git::get_repository(const boost::filesystem::pa
return instance;
}
boost::filesystem::path Git::path(const char *cpath, size_t cpath_length) noexcept {
boost::filesystem::path Git::path(const char *cpath, boost::optional<size_t> cpath_length_) noexcept {
if(cpath == nullptr)
return boost::filesystem::path();
if(cpath_length == static_cast<size_t>(-1))
cpath_length = strlen(cpath);
auto cpath_length = cpath_length_.value_or(strlen(cpath));
if(cpath_length > 0 && (cpath[cpath_length - 1] == '/' || cpath[cpath_length - 1] == '\\'))
return std::string(cpath, cpath_length - 1);
else

3
src/git.hpp

@ -1,6 +1,7 @@
#pragma once
#include "mutex.hpp"
#include <boost/filesystem.hpp>
#include <boost/optional.hpp>
#include <giomm.h>
#include <git2.h>
#include <iostream>
@ -98,7 +99,7 @@ private:
///Call initialize in public static methods
static void initialize() noexcept REQUIRES(mutex);
static boost::filesystem::path path(const char *cpath, size_t cpath_length = static_cast<size_t>(-1)) noexcept REQUIRES(mutex);
static boost::filesystem::path path(const char *cpath, boost::optional<size_t> cpath_length = {}) noexcept REQUIRES(mutex);
public:
static std::shared_ptr<Repository> get_repository(const boost::filesystem::path &path);

1
src/grep.cpp

@ -42,7 +42,6 @@ Grep::Grep(const boost::filesystem::path &path, const std::string &pattern, bool
std::string command = Config::get().project.grep_command + " -R " + flags + " --color=always --binary-files=without-match " + exclude + " -n " + escaped_pattern + " *";
std::stringstream stdin_stream;
//TODO: when debian stable gets newer g++ version that supports move on streams, remove unique_ptr below
Terminal::get().process(stdin_stream, output, command, project_path);
}

5
src/meson.cpp

@ -5,6 +5,7 @@
#include "filesystem.hpp"
#include "terminal.hpp"
#include "utility.hpp"
#include <boost/optional.hpp>
#include <regex>
Meson::Meson(const boost::filesystem::path &path) {
@ -94,7 +95,7 @@ bool Meson::update_debug_build(const boost::filesystem::path &debug_build_path,
boost::filesystem::path Meson::get_executable(const boost::filesystem::path &build_path, const boost::filesystem::path &file_path) {
CompileCommands compile_commands(build_path);
size_t best_match_size = -1;
boost::optional<size_t> best_match_size;
boost::filesystem::path best_match_executable;
for(auto &command : compile_commands.commands) {
auto command_file = filesystem::get_normal_path(command.file);
@ -109,7 +110,7 @@ boost::filesystem::path Meson::get_executable(const boost::filesystem::path &bui
auto command_file_directory = command_file.parent_path();
if(filesystem::file_in_path(file_path, command_file_directory)) {
auto size = static_cast<size_t>(std::distance(command_file_directory.begin(), command_file_directory.end()));
if(best_match_size == static_cast<size_t>(-1) || best_match_size < size) {
if(best_match_size < size) {
best_match_size = size;
best_match_executable = executable;
}

92
src/notebook.cpp

@ -52,7 +52,7 @@ Notebook::Notebook() : Gtk::Paned(), notebooks(2) {
break;
}
}
last_index = -1;
last_index.reset();
});
notebook.signal_page_added().connect([this](Gtk::Widget *widget, guint) {
auto hbox = dynamic_cast<Gtk::Box *>(widget);
@ -171,7 +171,7 @@ bool Notebook::open(const boost::filesystem::path &file_path_, Position position
auto previous_view = get_current_view();
if(previous_view) {
view->replace_text(previous_view->get_buffer()->get_text());
position = get_notebook_page(get_index(previous_view)).first == 0 ? Position::right : Position::left;
position = get_notebook_page(previous_view).first == 0 ? Position::right : Position::left;
}
}
@ -299,9 +299,7 @@ bool Notebook::open(const boost::filesystem::path &file_path_, Position position
//Set up tab label
tab_labels.emplace_back(new TabLabel([this, view]() {
auto index = get_index(view);
if(index != static_cast<size_t>(-1))
close(index);
close(get_index(view));
}));
view->update_tab_label = [this](Source::BaseView *view) {
std::string title = view->file_path.filename().string();
@ -311,9 +309,8 @@ bool Notebook::open(const boost::filesystem::path &file_path_, Position position
title += ' ';
for(size_t c = 0; c < size(); ++c) {
if(source_views[c] == view) {
auto &tab_label = tab_labels.at(c);
tab_label->label.set_text(title);
tab_label->set_tooltip_text(filesystem::get_short_path(view->file_path).string());
tab_labels[c]->label.set_text(title);
tab_labels[c]->set_tooltip_text(filesystem::get_short_path(view->file_path).string());
return;
}
}
@ -446,7 +443,7 @@ bool Notebook::open(const boost::filesystem::path &file_path_, Position position
else if(notebooks[1].get_n_pages() == 0)
position = Position::right;
else if(last_view)
position = get_notebook_page(get_index(last_view)).first == 0 ? Position::left : Position::right;
position = get_notebook_page(last_view).first == 0 ? Position::left : Position::right;
}
size_t notebook_index = position == Position::right ? 1 : 0;
auto &notebook = notebooks[notebook_index];
@ -458,11 +455,10 @@ bool Notebook::open(const boost::filesystem::path &file_path_, Position position
show_all_children();
notebook.set_current_page(notebook.get_n_pages() - 1);
last_index = -1;
last_index.reset();
if(last_view) {
auto index = get_index(last_view);
auto notebook_page = get_notebook_page(index);
if(notebook_page.first == notebook_index)
if(get_notebook_page(index).first == notebook_index)
last_index = index;
}
@ -517,17 +513,17 @@ bool Notebook::close(size_t index) {
}
if(view == get_current_view()) {
bool focused = false;
if(last_index != static_cast<size_t>(-1)) {
auto notebook_page = get_notebook_page(last_index);
if(notebook_page.first == get_notebook_page(get_index(view)).first) {
focus_view(source_views[last_index]);
notebooks[notebook_page.first].set_current_page(notebook_page.second);
last_index = -1;
if(last_index) {
auto last_notebook_page = get_notebook_page(*last_index);
if(get_notebook_page(view).first == last_notebook_page.first) {
focus_view(source_views[*last_index]);
notebooks[last_notebook_page.first].set_current_page(last_notebook_page.second);
last_index.reset();
focused = true;
}
}
if(!focused) {
auto notebook_page = get_notebook_page(get_index(view));
auto notebook_page = get_notebook_page(view);
if(notebook_page.second > 0)
focus_view(get_view(notebook_page.first, notebook_page.second - 1));
else {
@ -540,9 +536,9 @@ bool Notebook::close(size_t index) {
}
}
else if(index == last_index)
last_index = -1;
else if(index < last_index && last_index != static_cast<size_t>(-1))
last_index--;
last_index.reset();
else if(index < last_index)
(*last_index)--;
auto notebook_page = get_notebook_page(index);
notebooks[notebook_page.first].remove_page(notebook_page.second);
@ -600,7 +596,7 @@ bool Notebook::close_current() {
void Notebook::next() {
if(auto view = get_current_view()) {
auto notebook_page = get_notebook_page(get_index(view));
auto notebook_page = get_notebook_page(view);
int page = notebook_page.second + 1;
if(page >= notebooks[notebook_page.first].get_n_pages())
notebooks[notebook_page.first].set_current_page(0);
@ -611,7 +607,7 @@ void Notebook::next() {
void Notebook::previous() {
if(auto view = get_current_view()) {
auto notebook_page = get_notebook_page(get_index(view));
auto notebook_page = get_notebook_page(view);
int page = notebook_page.second - 1;
if(page < 0)
notebooks[notebook_page.first].set_current_page(notebooks[notebook_page.first].get_n_pages() - 1);
@ -634,8 +630,7 @@ void Notebook::toggle_split() {
}
else {
for(size_t c = size() - 1; c != static_cast<size_t>(-1); --c) {
auto notebook_index = get_notebook_page(c).first;
if(notebook_index == 1 && !close(c))
if(get_notebook_page(c).first == 1 && !close(c))
return;
}
remove(notebooks[1]);
@ -651,10 +646,8 @@ void Notebook::toggle_tabs() {
std::vector<std::pair<size_t, Source::View *>> Notebook::get_notebook_views() {
std::vector<std::pair<size_t, Source::View *>> notebook_views;
for(size_t notebook_index = 0; notebook_index < notebooks.size(); ++notebook_index) {
for(int page = 0; page < notebooks[notebook_index].get_n_pages(); ++page) {
if(auto view = get_view(notebook_index, page))
notebook_views.emplace_back(notebook_index, view);
}
for(int page = 0; page < notebooks[notebook_index].get_n_pages(); ++page)
notebook_views.emplace_back(notebook_index, get_view(notebook_index, page));
}
return notebook_views;
}
@ -680,19 +673,13 @@ void Notebook::clear_status() {
status_state.set_text("");
}
size_t Notebook::get_index(Source::View *view) {
for(size_t c = 0; c < size(); ++c) {
if(source_views[c] == view)
return c;
}
return -1;
}
Source::View *Notebook::get_view(size_t notebook_index, int page) {
if(notebook_index == static_cast<size_t>(-1) || notebook_index >= notebooks.size() ||
page < 0 || page >= notebooks[notebook_index].get_n_pages())
return nullptr;
auto hbox = dynamic_cast<Gtk::Box *>(notebooks[notebook_index].get_nth_page(page));
if(notebook_index >= notebooks.size())
throw "notebook index out of bounds";
auto widget = notebooks[notebook_index].get_nth_page(page);
if(!widget)
throw "page number out of bounds";
auto hbox = dynamic_cast<Gtk::Box *>(widget);
auto scrolled_window = dynamic_cast<Gtk::ScrolledWindow *>(hbox->get_children()[0]);
return dynamic_cast<Source::View *>(scrolled_window->get_children()[0]);
}
@ -702,15 +689,30 @@ void Notebook::focus_view(Source::View *view) {
view->grab_focus();
}
size_t Notebook::get_index(Source::View *view) {
for(size_t c = 0; c < size(); ++c) {
if(source_views[c] == view)
return c;
}
throw "view not found";
}
std::pair<size_t, int> Notebook::get_notebook_page(size_t index) {
if(index >= hboxes.size())
return {-1, -1};
for(size_t c = 0; c < notebooks.size(); ++c) {
auto page_num = notebooks[c].page_num(*hboxes[index]);
if(page_num >= 0)
return {c, page_num};
}
return {-1, -1};
throw "index out of bounds";
}
std::pair<size_t, int> Notebook::get_notebook_page(Source::View *view) {
try {
return get_notebook_page(get_index(view));
}
catch(...) {
throw "view not found";
}
}
void Notebook::set_current_view(Source::View *view) {

10
src/notebook.hpp

@ -1,5 +1,6 @@
#pragma once
#include "source.hpp"
#include <boost/optional.hpp>
#include <gtkmm.h>
#include <iostream>
#include <list>
@ -70,10 +71,15 @@ public:
void delete_cursor_locations(Source::View *view);
private:
size_t get_index(Source::View *view);
/// Throws on out of bounds arguments
Source::View *get_view(size_t notebook_index, int page);
void focus_view(Source::View *view);
/// Throws if view is not found
size_t get_index(Source::View *view);
/// Throws on out of bounds index
std::pair<size_t, int> get_notebook_page(size_t index);
/// Throws if view is not found
std::pair<size_t, int> get_notebook_page(Source::View *view);
std::vector<Gtk::Notebook> notebooks;
std::vector<Source::View *> source_views; //Is NOT freed in destructor, this is intended for quick program exit.
@ -83,7 +89,7 @@ private:
std::vector<std::unique_ptr<TabLabel>> tab_labels;
bool split = false;
size_t last_index = -1;
boost::optional<size_t> last_index;
void set_current_view(Source::View *view);
Source::View *current_view = nullptr;

6
src/selection_dialog.cpp

@ -150,7 +150,7 @@ void SelectionDialogBase::cursor_changed() {
if(!is_visible())
return;
auto it = list_view_text.get_selection()->get_selected();
auto index = static_cast<unsigned int>(-1);
boost::optional<unsigned int> index;
if(it)
index = it->get_value(list_view_text.column_record.index);
if(last_index == index)
@ -159,7 +159,7 @@ void SelectionDialogBase::cursor_changed() {
std::string text;
if(it)
text = it->get_value(list_view_text.column_record.text);
on_changed(index, text);
on_changed(index.value_or(-1), text);
}
last_index = index;
}
@ -208,7 +208,7 @@ void SelectionDialogBase::hide() {
if(on_hide)
on_hide();
list_view_text.clear();
last_index = static_cast<unsigned int>(-1);
last_index.reset();
}
std::unique_ptr<SelectionDialog> SelectionDialog::instance;

3
src/selection_dialog.hpp

@ -1,4 +1,5 @@
#pragma once
#include <boost/optional.hpp>
#include <functional>
#include <gtkmm.h>
#include <unordered_map>
@ -65,7 +66,7 @@ protected:
SearchEntry search_entry;
bool show_search_entry;
unsigned int last_index = static_cast<unsigned int>(-1);
boost::optional<unsigned int> last_index;
};
class SelectionDialog : public SelectionDialogBase {

31
src/source.cpp

@ -235,7 +235,7 @@ Source::View::View(const boost::filesystem::path &file_path, const Glib::RefPtr<
--line_end;
bool lines_commented = true;
bool extra_spaces = true;
int min_indentation = -1;
boost::optional<int> min_indentation;
for(auto line = line_start; line <= line_end; ++line) {
auto iter = get_buffer()->get_iter_at_line(line);
bool line_added = false;
@ -281,7 +281,7 @@ Source::View::View(const boost::filesystem::path &file_path, const Glib::RefPtr<
if(line_added) {
lines_commented &= line_commented;
extra_spaces &= extra_space;
if(min_indentation == -1 || indentation < min_indentation)
if(!min_indentation || indentation < min_indentation)
min_indentation = indentation;
}
}
@ -290,7 +290,7 @@ Source::View::View(const boost::filesystem::path &file_path, const Glib::RefPtr<
get_buffer()->begin_user_action();
for(auto &line : lines) {
auto iter = get_buffer()->get_iter_at_line(line);
iter.forward_chars(min_indentation);
iter.forward_chars(min_indentation.value_or(0));
if(lines_commented) {
auto end_iter = iter;
end_iter.forward_chars(comment_characters.size() + static_cast<int>(extra_spaces));
@ -420,7 +420,7 @@ bool Source::View::save() {
boost::system::error_code ec;
last_write_time = boost::filesystem::last_write_time(file_path, ec);
if(ec)
last_write_time = static_cast<std::time_t>(-1);
last_write_time.reset();
// Remonitor file in case it did not exist before
monitor_file();
get_buffer()->set_modified(false);
@ -578,9 +578,7 @@ void Source::View::setup_signals() {
if(on_motion_last_x != event->x || on_motion_last_y != event->y) {
delayed_tooltips_connection.disconnect();
if((event->state & GDK_BUTTON1_MASK) == 0) {
gdouble x = event->x;
gdouble y = event->y;
delayed_tooltips_connection = Glib::signal_timeout().connect([this, x, y]() {
delayed_tooltips_connection = Glib::signal_timeout().connect([this, x = event->x, y = event->y]() {
type_tooltips.hide();
diagnostic_tooltips.hide();
Tooltips::init();
@ -610,8 +608,8 @@ void Source::View::setup_signals() {
}, 100);
}
auto last_mouse_pos = std::make_pair(on_motion_last_x, on_motion_last_y);
auto mouse_pos = std::make_pair(event->x, event->y);
auto last_mouse_pos = std::make_pair<int, int>(on_motion_last_x, on_motion_last_y);
auto mouse_pos = std::make_pair<int, int>(event->x, event->y);
type_tooltips.hide(last_mouse_pos, mouse_pos);
diagnostic_tooltips.hide(last_mouse_pos, mouse_pos);
}
@ -1350,7 +1348,7 @@ void Source::View::extend_selection() {
if(!select_matching_brackets) {
bool select_end_block = language->get_id() == "cmake" || language->get_id() == "meson";
auto get_tabs = [this](Gtk::TextIter iter) {
auto get_tabs = [this](Gtk::TextIter iter) -> boost::optional<int> {
iter = get_buffer()->get_iter_at_line(iter.get_line());
int tabs = 0;
while(!iter.ends_line() && (*iter == ' ' || *iter == '\t')) {
@ -1359,7 +1357,7 @@ void Source::View::extend_selection() {
break;
}
if(iter.ends_line())
return -1;
return {};
return tabs;
};
@ -1380,19 +1378,18 @@ void Source::View::extend_selection() {
end.forward_to_line_end();
// Try select block that starts at cursor
auto end_tabs = get_tabs(end);
auto iter = end;
if(end_tabs >= 0) {
if(auto end_tabs = get_tabs(end)) {
bool can_select_end_block = false;
while(iter.forward_char()) {
auto tabs = get_tabs(iter);
if(tabs < 0 || tabs > end_tabs || (select_end_block && can_select_end_block && tabs == end_tabs)) {
if(!tabs || tabs > end_tabs || (select_end_block && can_select_end_block && tabs == end_tabs)) {
if(!iter.ends_line())
iter.forward_to_line_end();
end = iter;
if(tabs > end_tabs)
can_select_end_block = true;
if(tabs == end_tabs)
else if(tabs == end_tabs)
break;
continue;
}
@ -3072,7 +3069,7 @@ bool Source::View::on_key_press_event_smart_inserts(GdkEventKey *key) {
}
}
// Insert ''
else if(key->keyval == GDK_KEY_apostrophe && allow_insertion(iter) && symbol_count(iter, '\'', -1) % 2 == 0) {
else if(key->keyval == GDK_KEY_apostrophe && allow_insertion(iter) && symbol_count(iter, '\'') % 2 == 0) {
get_buffer()->insert_at_cursor("''");
auto iter = get_buffer()->get_insert()->get_iter();
iter.backward_char();
@ -3081,7 +3078,7 @@ bool Source::View::on_key_press_event_smart_inserts(GdkEventKey *key) {
return true;
}
// Insert ""
else if(key->keyval == GDK_KEY_quotedbl && allow_insertion(iter) && symbol_count(iter, '"', -1) % 2 == 0) {
else if(key->keyval == GDK_KEY_quotedbl && allow_insertion(iter) && symbol_count(iter, '"') % 2 == 0) {
get_buffer()->insert_at_cursor("\"\"");
auto iter = get_buffer()->get_insert()->get_iter();
iter.backward_char();

2
src/source.hpp

@ -134,7 +134,7 @@ namespace Source {
Gtk::TextIter get_start_of_expression(Gtk::TextIter iter);
bool find_close_symbol_forward(Gtk::TextIter iter, Gtk::TextIter &found_iter, unsigned int positive_char, unsigned int negative_char);
bool find_open_symbol_backward(Gtk::TextIter iter, Gtk::TextIter &found_iter, unsigned int positive_char, unsigned int negative_char);
long symbol_count(Gtk::TextIter iter, unsigned int positive_char, unsigned int negative_char);
long symbol_count(Gtk::TextIter iter, unsigned int positive_char, unsigned int negative_char = 0);
bool is_templated_function(Gtk::TextIter iter, Gtk::TextIter &parenthesis_end_iter);
/// If insert is at an possible argument. Also based on last key press.
bool is_possible_argument();

30
src/source_base.cpp

@ -129,7 +129,7 @@ Source::BaseView::BaseView(const boost::filesystem::path &file_path, const Glib:
get_buffer()->place_cursor(get_buffer()->get_iter_at_offset(0));
signal_focus_in_event().connect([this](GdkEventFocus *event) {
if(this->last_write_time != static_cast<std::time_t>(-1))
if(last_write_time)
check_last_write_time();
return false;
});
@ -202,7 +202,7 @@ bool Source::BaseView::load(bool not_undoable_action) {
boost::system::error_code ec;
last_write_time = boost::filesystem::last_write_time(file_path, ec);
if(ec)
last_write_time = static_cast<std::time_t>(-1);
last_write_time.reset();
disable_spellcheck = true;
if(not_undoable_action)
@ -312,7 +312,7 @@ void Source::BaseView::rename(const boost::filesystem::path &path) {
boost::system::error_code ec;
last_write_time = boost::filesystem::last_write_time(file_path, ec);
if(ec)
last_write_time = static_cast<std::time_t>(-1);
last_write_time.reset();
monitor_file();
if(update_status_file_path)
@ -325,7 +325,7 @@ void Source::BaseView::monitor_file() {
#ifdef __APPLE__ // TODO: Gio file monitor is bugged on MacOS
class Recursive {
public:
static void f(BaseView *view, std::time_t previous_last_write_time = static_cast<std::time_t>(-1), bool check_called = false) {
static void f(BaseView *view, boost::optional<std::time_t> previous_last_write_time = {}, bool check_called = false) {
view->delayed_monitor_changed_connection.disconnect();
view->delayed_monitor_changed_connection = Glib::signal_timeout().connect([view, previous_last_write_time, check_called]() {
boost::system::error_code ec;
@ -346,10 +346,10 @@ void Source::BaseView::monitor_file() {
}
};
delayed_monitor_changed_connection.disconnect();
if(last_write_time != static_cast<std::time_t>(-1))
if(last_write_time)
Recursive::f(this);
#else
if(this->last_write_time != static_cast<std::time_t>(-1)) {
if(last_write_time) {
monitor = Gio::File::create_for_path(file_path.string())->monitor_file(Gio::FileMonitorFlags::FILE_MONITOR_NONE);
monitor_changed_connection.disconnect();
monitor_changed_connection = monitor->signal_changed().connect([this](const Glib::RefPtr<Gio::File> &file,
@ -367,13 +367,13 @@ void Source::BaseView::monitor_file() {
#endif
}
void Source::BaseView::check_last_write_time(std::time_t last_write_time_) {
if(this->last_write_time == static_cast<std::time_t>(-1))
void Source::BaseView::check_last_write_time(boost::optional<std::time_t> last_write_time_) {
if(!this->last_write_time)
return;
if(Config::get().source.auto_reload_changed_files && !get_buffer()->get_modified()) {
boost::system::error_code ec;
auto last_write_time = last_write_time_ != static_cast<std::time_t>(-1) ? last_write_time_ : boost::filesystem::last_write_time(file_path, ec);
auto last_write_time = last_write_time_.value_or(boost::filesystem::last_write_time(file_path, ec));
if(!ec && last_write_time != this->last_write_time) {
if(load())
return;
@ -381,7 +381,7 @@ void Source::BaseView::check_last_write_time(std::time_t last_write_time_) {
}
else if(has_focus()) {
boost::system::error_code ec;
auto last_write_time = last_write_time_ != static_cast<std::time_t>(-1) ? last_write_time_ : boost::filesystem::last_write_time(file_path, ec);
auto last_write_time = last_write_time_.value_or(boost::filesystem::last_write_time(file_path, ec));
if(!ec && last_write_time != this->last_write_time)
Info::get().print("Caution: " + file_path.filename().string() + " was changed outside of juCi++");
}
@ -820,7 +820,7 @@ void Source::BaseView::paste() {
size_t end_line = 0;
bool paste_line = false;
bool first_paste_line = true;
size_t paste_line_tabs = -1;
auto paste_line_tabs = static_cast<size_t>(-1);
bool first_paste_line_has_tabs = false;
for(size_t c = 0; c < text.size(); c++) {
if(text[c] == '\n') {
@ -1161,7 +1161,7 @@ void Source::BaseView::setup_extra_cursor_signals() {
extra_cursor.offset = extra_cursor_iter.get_line_offset();
}
for(auto &extra_cursor : extra_snippet_cursors) {
extra_cursor.initial_forward_erase_size = std::numeric_limits<int>::max();
extra_cursor.initial_forward_erase_size.reset();
auto iter = extra_cursor.mark->get_iter();
iter.forward_chars(offset);
get_buffer()->insert(iter, text);
@ -1196,9 +1196,9 @@ void Source::BaseView::setup_extra_cursor_signals() {
auto start_iter = extra_cursor.mark->get_iter();
auto end_iter = start_iter;
start_iter.backward_chars(*erase_backward_length);
if(extra_cursor.initial_forward_erase_size != std::numeric_limits<int>::max()) { // In case of different sized placeholders
end_iter.forward_chars(extra_cursor.initial_forward_erase_size);
extra_cursor.initial_forward_erase_size = std::numeric_limits<int>::max();
if(extra_cursor.initial_forward_erase_size) { // In case of different sized placeholders
end_iter.forward_chars(*extra_cursor.initial_forward_erase_size);
extra_cursor.initial_forward_erase_size.reset();
}
else
end_iter.forward_chars(*erase_forward_length);

7
src/source_base.hpp

@ -3,6 +3,7 @@
#include "mutex.hpp"
#include "snippets.hpp"
#include <boost/filesystem.hpp>
#include <boost/optional.hpp>
#include <gtksourceviewmm.h>
#include <list>
#include <regex>
@ -96,9 +97,9 @@ namespace Source {
bool keep_clipboard = false;
protected:
std::time_t last_write_time;
boost::optional<std::time_t> last_write_time;
void monitor_file();
void check_last_write_time(std::time_t last_write_time_ = static_cast<std::time_t>(-1));
void check_last_write_time(boost::optional<std::time_t> last_write_time_ = {});
bool is_bracket_language = false;
@ -148,7 +149,7 @@ namespace Source {
std::vector<ExtraCursor> extra_cursors;
struct ExtraSnippetCursor {
Glib::RefPtr<Gtk::TextBuffer::Mark> mark;
int initial_forward_erase_size;
boost::optional<int> initial_forward_erase_size;
};
bool on_key_press_event_extra_cursors(GdkEventKey *key);

23
src/source_language_protocol.cpp

@ -189,9 +189,6 @@ void LanguageProtocol::Client::close(Source::LanguageProtocolView *view) {
void LanguageProtocol::Client::parse_server_message() {
if(!header_read) {
server_message_size = static_cast<size_t>(-1);
server_message_stream.seekg(0, std::ios::beg);
std::string line;
while(!header_read && std::getline(server_message_stream, line)) {
if(!line.empty() && line != "\r") {
@ -203,9 +200,9 @@ void LanguageProtocol::Client::parse_server_message() {
}
}
}
else if(server_message_size != static_cast<size_t>(-1)) {
else if(server_message_size) {
server_message_content_pos = server_message_stream.tellg();
server_message_size += server_message_content_pos;
*server_message_size += server_message_content_pos;
header_read = true;
}
}
@ -215,11 +212,11 @@ void LanguageProtocol::Client::parse_server_message() {
server_message_stream.seekg(0, std::ios::end);
size_t read_size = server_message_stream.tellg();
std::stringstream tmp;
if(read_size >= server_message_size) {
if(read_size > server_message_size) {
server_message_stream.seekg(server_message_size, std::ios::beg);
server_message_stream.seekp(server_message_size, std::ios::beg);
for(size_t c = server_message_size; c < read_size; ++c) {
if(read_size >= *server_message_size) {
if(read_size > *server_message_size) {
server_message_stream.seekg(*server_message_size, std::ios::beg);
server_message_stream.seekp(*server_message_size, std::ios::beg);
for(size_t c = *server_message_size; c < read_size; ++c) {
tmp.put(server_message_stream.get());
server_message_stream.put(' ');
}
@ -279,13 +276,13 @@ void LanguageProtocol::Client::parse_server_message() {
}
server_message_stream = std::stringstream();
server_message_size.reset();
header_read = false;
server_message_size = static_cast<size_t>(-1);
tmp.seekg(0, std::ios::end);
if(tmp.tellg() > 0) {
tmp.seekg(0, std::ios::beg);
server_message_stream << tmp.rdbuf();
server_message_stream = std::move(tmp);
server_message_stream.seekg(0, std::ios::beg);
parse_server_message();
}
}

3
src/source_language_protocol.hpp

@ -4,6 +4,7 @@
#include "process.hpp"
#include "source.hpp"
#include <atomic>
#include <boost/optional.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <list>
#include <map>
@ -118,7 +119,7 @@ namespace LanguageProtocol {
std::unique_ptr<TinyProcessLib::Process> process GUARDED_BY(read_write_mutex);
std::stringstream server_message_stream;
size_t server_message_size = static_cast<size_t>(-1);
boost::optional<size_t> server_message_size;
size_t server_message_content_pos;
bool header_read = false;

50
src/terminal.cpp

@ -165,7 +165,7 @@ bool Terminal::on_motion_notify_event(GdkEventMotion *event) {
return Gtk::TextView::on_motion_notify_event(event);
}
std::tuple<size_t, size_t, std::string, std::string, std::string> Terminal::find_link(const std::string &line) {
boost::optional<Terminal::Link> Terminal::find_link(const std::string &line) {
const static std::regex link_regex("^([A-Z]:)?([^:]+):([0-9]+):([0-9]+): .*$|" // C/C++ compile warning/error/rename usages
"^ --> ([A-Z]:)?([^:]+):([0-9]+):([0-9]+)$|" // Rust
"^Assertion failed: .*file ([A-Z]:)?([^:]+), line ([0-9]+)\\.$|" // clang assert()
@ -173,26 +173,30 @@ std::tuple<size_t, size_t, std::string, std::string, std::string> Terminal::find
"^ERROR:([A-Z]:)?([^:]+):([0-9]+):.*$|" // g_assert (glib.h)
"^([A-Z]:)?([\\/][^:]+):([0-9]+)$|" // Node.js
"^ File \"([A-Z]:)?([^\"]+)\", line ([0-9]+), in .*$"); // Python
size_t start_position = -1, end_position = -1;
std::string path, line_number, line_offset;
std::smatch sm;
if(std::regex_match(line, sm, link_regex)) {
for(size_t sub = 1; sub < link_regex.mark_count();) {
size_t subs = sub == 1 || sub == 5 ? 4 : 3;
if(sm.length(sub + 1)) {
start_position = sm.position(sub + 1) - sm.length(sub);
end_position = sm.position(sub + subs - 1) + sm.length(sub + subs - 1);
auto start_pos = static_cast<int>(sm.position(sub + 1) - sm.length(sub));
auto end_pos = static_cast<int>(sm.position(sub + subs - 1) + sm.length(sub + subs - 1));
std::string path;
if(sm.length(sub))
path += sm[sub].str();
path = sm[sub].str();
path += sm[sub + 1].str();
line_number = sm[sub + 2].str();
line_offset = subs == 4 ? sm[sub + 3].str() : "1";
break;
try {
auto line_number = std::stoi(sm[sub + 2].str());
auto line_offset = std::stoi(subs == 4 ? sm[sub + 3].str() : "1");
return Link{start_pos, end_pos, path, line_number, line_offset};
}
catch(...) {
return {};
}
}
sub += subs;
}
}
return std::make_tuple(start_position, end_position, path, line_number, line_offset);
return {};
}
void Terminal::apply_link_tags(const Gtk::TextIter &start_iter, const Gtk::TextIter &end_iter) {
@ -224,11 +228,11 @@ void Terminal::apply_link_tags(const Gtk::TextIter &start_iter, const Gtk::TextI
line.replace(c, 1, "a");
}
auto link = find_link(line.raw());
if(std::get<0>(link) != static_cast<size_t>(-1)) {
if(link) {
auto link_start = line_start;
auto link_end = line_start;
link_start.forward_chars(std::get<0>(link));
link_end.forward_chars(std::get<1>(link));
link_start.forward_chars(link->start_pos);
link_end.forward_chars(link->end_pos);
get_buffer()->apply_tag(link_tag, link_start, link_end);
}
line_start_set = false;
@ -356,10 +360,8 @@ bool Terminal::on_button_press_event(GdkEventButton *button_event) {
while(!end_iter.ends_line() && end_iter.forward_char()) {
}
auto link = find_link(get_buffer()->get_text(start_iter, end_iter).raw());
if(std::get<0>(link) != static_cast<size_t>(-1)) {
auto path = filesystem::get_long_path(std::get<2>(link));
std::string line = std::get<3>(link);
std::string index = std::get<4>(link);
if(link) {
auto path = filesystem::get_long_path(link->path);
if(path.is_relative()) {
if(Project::current) {
@ -379,16 +381,10 @@ bool Terminal::on_button_press_event(GdkEventButton *button_event) {
boost::system::error_code ec;
if(boost::filesystem::is_regular_file(path, ec)) {
if(Notebook::get().open(path)) {
try {
int line_int = std::stoi(line) - 1;
int index_int = std::stoi(index) - 1;
auto view = Notebook::get().get_current_view();
view->place_cursor_at_line_index(line_int, index_int);
view->scroll_to_cursor_delayed(true, true);
return true;
}
catch(...) {
}
auto view = Notebook::get().get_current_view();
view->place_cursor_at_line_index(link->line - 1, link->line_index - 1);
view->scroll_to_cursor_delayed(true, true);
return true;
}
}
}

8
src/terminal.hpp

@ -4,6 +4,7 @@
#include "process.hpp"
#include "source_base.hpp"
#include <boost/filesystem.hpp>
#include <boost/optional.hpp>
#include <functional>
#include <gtkmm.h>
#include <iostream>
@ -45,7 +46,12 @@ private:
Glib::RefPtr<Gdk::Cursor> default_mouse_cursor;
size_t deleted_lines = 0;
std::tuple<size_t, size_t, std::string, std::string, std::string> find_link(const std::string &line);
struct Link {
int start_pos, end_pos;
std::string path;
int line, line_index;
};
boost::optional<Link> find_link(const std::string &line);
void apply_link_tags(const Gtk::TextIter &start_iter, const Gtk::TextIter &end_iter);
Mutex processes_mutex;

14
src/tooltips.cpp

@ -287,14 +287,14 @@ void Tooltip::show(bool disregard_drawn, const std::function<void()> &on_motion)
shown = true;
}
void Tooltip::hide(const std::pair<int, int> &last_mouse_pos, const std::pair<int, int> &mouse_pos) {
void Tooltip::hide(const boost::optional<std::pair<int, int>> &last_mouse_pos, const boost::optional<std::pair<int, int>> &mouse_pos) {
// Keep tooltip if mouse is moving towards it
// Calculated using dot product between the mouse_pos vector and the corners of the tooltip window
if(text_view && window && shown && last_mouse_pos.first != -1 && last_mouse_pos.second != -1 && mouse_pos.first != -1 && mouse_pos.second != -1) {
if(text_view && window && shown && last_mouse_pos && mouse_pos) {
static int root_x, root_y;
text_view->get_window(Gtk::TextWindowType::TEXT_WINDOW_TEXT)->get_root_coords(last_mouse_pos.first, last_mouse_pos.second, root_x, root_y);
int diff_x = mouse_pos.first - last_mouse_pos.first;
int diff_y = mouse_pos.second - last_mouse_pos.second;
text_view->get_window(Gtk::TextWindowType::TEXT_WINDOW_TEXT)->get_root_coords(last_mouse_pos->first, last_mouse_pos->second, root_x, root_y);
int diff_x = mouse_pos->first - last_mouse_pos->first;
int diff_y = mouse_pos->second - last_mouse_pos->second;
class Corner {
public:
Corner(int x, int y) : x(x - root_x), y(y - root_y) {}
@ -792,7 +792,7 @@ void Tooltips::show(const Gdk::Rectangle &rectangle, bool disregard_drawn) {
if(rectangle.intersects(tooltip.activation_rectangle))
tooltip.show(disregard_drawn, on_motion);
else
tooltip.hide();
tooltip.hide({}, {});
}
}
@ -803,7 +803,7 @@ void Tooltips::show(bool disregard_drawn) {
}
}
void Tooltips::hide(const std::pair<int, int> &last_mouse_pos, const std::pair<int, int> &mouse_pos) {
void Tooltips::hide(boost::optional<std::pair<int, int>> last_mouse_pos, boost::optional<std::pair<int, int>> mouse_pos) {
for(auto &tooltip : tooltip_list)
tooltip.hide(last_mouse_pos, mouse_pos);
}

5
src/tooltips.hpp

@ -1,4 +1,5 @@
#pragma once
#include <boost/optional.hpp>
#include <functional>
#include <gtkmm.h>
#include <list>
@ -14,7 +15,7 @@ public:
void update();
void show(bool disregard_drawn = false, const std::function<void()> &on_motion = nullptr);
void hide(const std::pair<int, int> &last_mouse_pos = {-1, -1}, const std::pair<int, int> &mouse_pos = {-1, -1});
void hide(const boost::optional<std::pair<int, int>> &last_mouse_pos, const boost::optional<std::pair<int, int>> &mouse_pos);
Gdk::Rectangle activation_rectangle;
Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark;
@ -61,7 +62,7 @@ public:
void show(const Gdk::Rectangle &rectangle, bool disregard_drawn = false);
void show(bool disregard_drawn = false);
void hide(const std::pair<int, int> &last_mouse_pos = {-1, -1}, const std::pair<int, int> &mouse_pos = {-1, -1});
void hide(boost::optional<std::pair<int, int>> last_mouse_pos = {}, boost::optional<std::pair<int, int>> mouse_pos = {});
void clear() { tooltip_list.clear(); };
template <typename... Ts>

41
tests/terminal_test.cpp

@ -13,31 +13,38 @@ int main() {
{
auto link = Terminal::get().find_link("~/test/test.cc:7:41: error: expected ';' after expression.");
assert(std::get<0>(link) == 0);
assert(std::get<1>(link) == 19);
assert(std::get<2>(link) == "~/test/test.cc");
assert(std::get<3>(link) == "7");
assert(std::get<4>(link) == "41");
assert(link);
assert(link->start_pos == 0);
assert(link->end_pos == 19);
assert(link->path == "~/test/test.cc");
assert(link->line == 7);
assert(link->line_index == 41);
}
{
auto link = Terminal::get().find_link("Assertion failed: (false), function main, file ~/test/test.cc, line 15.");
assert(std::get<0>(link) == 47);
assert(std::get<1>(link) == 70);
assert(std::get<2>(link) == "~/test/test.cc");
assert(std::get<3>(link) == "15");
assert(link);
assert(link->start_pos == 47);
assert(link->end_pos == 70);
assert(link->path == "~/test/test.cc");
assert(link->line == 15);
assert(link->line_index == 1);
}
{
auto link = Terminal::get().find_link("test: ~/examples/main.cpp:17: int main(int, char**): Assertion `false' failed.");
assert(std::get<0>(link) == 6);
assert(std::get<1>(link) == 28);
assert(std::get<2>(link) == "~/examples/main.cpp");
assert(std::get<3>(link) == "17");
assert(link);
assert(link->start_pos == 6);
assert(link->end_pos == 28);
assert(link->path == "~/examples/main.cpp");
assert(link->line == 17);
assert(link->line_index == 1);
}
{
auto link = Terminal::get().find_link("ERROR:~/test/test.cc:36:int main(): assertion failed: (false)");
assert(std::get<0>(link) == 6);
assert(std::get<1>(link) == 23);
assert(std::get<2>(link) == "~/test/test.cc");
assert(std::get<3>(link) == "36");
assert(link);
assert(link->start_pos == 6);
assert(link->end_pos == 23);
assert(link->path == "~/test/test.cc");
assert(link->line == 36);
assert(link->line_index == 1);
}
}

Loading…
Cancel
Save