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. 44
      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 "filesystem.hpp"
#include "terminal.hpp" #include "terminal.hpp"
#include "utility.hpp" #include "utility.hpp"
#include <boost/optional.hpp>
#include <regex> #include <regex>
CMake::CMake(const boost::filesystem::path &path) { 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; boost::filesystem::path best_match_executable;
for(auto &cmake_executable : cmake_executables) { 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(); auto command_file_directory = command_file.parent_path();
if(filesystem::file_in_path(file_path, command_file_directory)) { 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())); 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_size = size;
best_match_executable = maybe_executable; 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(); auto command_file_directory = command_file.parent_path();
if(filesystem::file_in_path(file_path, command_file_directory)) { 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())); 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_size = size;
best_match_executable = maybe_executable; best_match_executable = maybe_executable;
} }

10
src/documentation.cpp

@ -1,6 +1,10 @@
#include "documentation.hpp" #include "documentation.hpp"
#include <unordered_map> #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 { 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 // Extracted from http://upload.cppreference.com/mwiki/images/b/b1/cppreference-doc-20190607.zip
// Using raw string instead of map to reduce compile time // Using raw string instead of map to reduce compile time
@ -1908,7 +1912,7 @@ std::ignore tuple
std::ranges::swap concepts std::ranges::swap concepts
std::forward utility std::forward utility
std::exchange utility std::exchange utility
std::move (utility) utility std::move utility
std::move_if_noexcept utility std::move_if_noexcept utility
std::declval utility std::declval utility
std::as_const utility std::as_const utility
@ -2342,7 +2346,6 @@ std::copy algorithm
std::copy_if algorithm std::copy_if algorithm
std::copy_n algorithm std::copy_n algorithm
std::copy_backward algorithm std::copy_backward algorithm
std::move (algorithm) algorithm
std::move_backward algorithm std::move_backward algorithm
std::fill algorithm std::fill algorithm
std::fill_n algorithm std::fill_n algorithm
@ -5939,7 +5942,7 @@ std::ignore cpp/utility/tuple/ignore
std::ranges::swap cpp/utility/ranges/swap std::ranges::swap cpp/utility/ranges/swap
std::forward cpp/utility/forward std::forward cpp/utility/forward
std::exchange cpp/utility/exchange 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::move_if_noexcept cpp/utility/move_if_noexcept
std::declval cpp/utility/declval std::declval cpp/utility/declval
std::as_const cpp/utility/as_const std::as_const cpp/utility/as_const
@ -9073,7 +9076,6 @@ std::copy cpp/algorithm/copy
std::copy_if cpp/algorithm/copy std::copy_if cpp/algorithm/copy
std::copy_n cpp/algorithm/copy_n std::copy_n cpp/algorithm/copy_n
std::copy_backward cpp/algorithm/copy_backward std::copy_backward cpp/algorithm/copy_backward
std::move (algorithm) cpp/algorithm/move
std::move_backward cpp/algorithm/move_backward std::move_backward cpp/algorithm/move_backward
std::fill cpp/algorithm/fill std::fill cpp/algorithm/fill
std::fill_n cpp/algorithm/fill_n 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; 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) if(cpath == nullptr)
return boost::filesystem::path(); return boost::filesystem::path();
if(cpath_length == static_cast<size_t>(-1)) auto cpath_length = cpath_length_.value_or(strlen(cpath));
cpath_length = strlen(cpath);
if(cpath_length > 0 && (cpath[cpath_length - 1] == '/' || cpath[cpath_length - 1] == '\\')) if(cpath_length > 0 && (cpath[cpath_length - 1] == '/' || cpath[cpath_length - 1] == '\\'))
return std::string(cpath, cpath_length - 1); return std::string(cpath, cpath_length - 1);
else else

3
src/git.hpp

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "mutex.hpp" #include "mutex.hpp"
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/optional.hpp>
#include <giomm.h> #include <giomm.h>
#include <git2.h> #include <git2.h>
#include <iostream> #include <iostream>
@ -98,7 +99,7 @@ private:
///Call initialize in public static methods ///Call initialize in public static methods
static void initialize() noexcept REQUIRES(mutex); 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: public:
static std::shared_ptr<Repository> get_repository(const boost::filesystem::path &path); 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::string command = Config::get().project.grep_command + " -R " + flags + " --color=always --binary-files=without-match " + exclude + " -n " + escaped_pattern + " *";
std::stringstream stdin_stream; 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); Terminal::get().process(stdin_stream, output, command, project_path);
} }

5
src/meson.cpp

@ -5,6 +5,7 @@
#include "filesystem.hpp" #include "filesystem.hpp"
#include "terminal.hpp" #include "terminal.hpp"
#include "utility.hpp" #include "utility.hpp"
#include <boost/optional.hpp>
#include <regex> #include <regex>
Meson::Meson(const boost::filesystem::path &path) { 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) { boost::filesystem::path Meson::get_executable(const boost::filesystem::path &build_path, const boost::filesystem::path &file_path) {
CompileCommands compile_commands(build_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; boost::filesystem::path best_match_executable;
for(auto &command : compile_commands.commands) { for(auto &command : compile_commands.commands) {
auto command_file = filesystem::get_normal_path(command.file); 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(); auto command_file_directory = command_file.parent_path();
if(filesystem::file_in_path(file_path, command_file_directory)) { 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())); 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_size = size;
best_match_executable = executable; best_match_executable = executable;
} }

92
src/notebook.cpp

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

10
src/notebook.hpp

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

6
src/selection_dialog.cpp

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

3
src/selection_dialog.hpp

@ -1,4 +1,5 @@
#pragma once #pragma once
#include <boost/optional.hpp>
#include <functional> #include <functional>
#include <gtkmm.h> #include <gtkmm.h>
#include <unordered_map> #include <unordered_map>
@ -65,7 +66,7 @@ protected:
SearchEntry search_entry; SearchEntry search_entry;
bool show_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 { 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; --line_end;
bool lines_commented = true; bool lines_commented = true;
bool extra_spaces = true; bool extra_spaces = true;
int min_indentation = -1; boost::optional<int> min_indentation;
for(auto line = line_start; line <= line_end; ++line) { for(auto line = line_start; line <= line_end; ++line) {
auto iter = get_buffer()->get_iter_at_line(line); auto iter = get_buffer()->get_iter_at_line(line);
bool line_added = false; bool line_added = false;
@ -281,7 +281,7 @@ Source::View::View(const boost::filesystem::path &file_path, const Glib::RefPtr<
if(line_added) { if(line_added) {
lines_commented &= line_commented; lines_commented &= line_commented;
extra_spaces &= extra_space; extra_spaces &= extra_space;
if(min_indentation == -1 || indentation < min_indentation) if(!min_indentation || indentation < min_indentation)
min_indentation = 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(); get_buffer()->begin_user_action();
for(auto &line : lines) { for(auto &line : lines) {
auto iter = get_buffer()->get_iter_at_line(line); 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) { if(lines_commented) {
auto end_iter = iter; auto end_iter = iter;
end_iter.forward_chars(comment_characters.size() + static_cast<int>(extra_spaces)); 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; boost::system::error_code ec;
last_write_time = boost::filesystem::last_write_time(file_path, ec); last_write_time = boost::filesystem::last_write_time(file_path, ec);
if(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 // Remonitor file in case it did not exist before
monitor_file(); monitor_file();
get_buffer()->set_modified(false); 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) { if(on_motion_last_x != event->x || on_motion_last_y != event->y) {
delayed_tooltips_connection.disconnect(); delayed_tooltips_connection.disconnect();
if((event->state & GDK_BUTTON1_MASK) == 0) { if((event->state & GDK_BUTTON1_MASK) == 0) {
gdouble x = event->x; delayed_tooltips_connection = Glib::signal_timeout().connect([this, x = event->x, y = event->y]() {
gdouble y = event->y;
delayed_tooltips_connection = Glib::signal_timeout().connect([this, x, y]() {
type_tooltips.hide(); type_tooltips.hide();
diagnostic_tooltips.hide(); diagnostic_tooltips.hide();
Tooltips::init(); Tooltips::init();
@ -610,8 +608,8 @@ void Source::View::setup_signals() {
}, 100); }, 100);
} }
auto last_mouse_pos = std::make_pair(on_motion_last_x, on_motion_last_y); auto last_mouse_pos = std::make_pair<int, int>(on_motion_last_x, on_motion_last_y);
auto mouse_pos = std::make_pair(event->x, event->y); auto mouse_pos = std::make_pair<int, int>(event->x, event->y);
type_tooltips.hide(last_mouse_pos, mouse_pos); type_tooltips.hide(last_mouse_pos, mouse_pos);
diagnostic_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) { if(!select_matching_brackets) {
bool select_end_block = language->get_id() == "cmake" || language->get_id() == "meson"; 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()); iter = get_buffer()->get_iter_at_line(iter.get_line());
int tabs = 0; int tabs = 0;
while(!iter.ends_line() && (*iter == ' ' || *iter == '\t')) { while(!iter.ends_line() && (*iter == ' ' || *iter == '\t')) {
@ -1359,7 +1357,7 @@ void Source::View::extend_selection() {
break; break;
} }
if(iter.ends_line()) if(iter.ends_line())
return -1; return {};
return tabs; return tabs;
}; };
@ -1380,19 +1378,18 @@ void Source::View::extend_selection() {
end.forward_to_line_end(); end.forward_to_line_end();
// Try select block that starts at cursor // Try select block that starts at cursor
auto end_tabs = get_tabs(end);
auto iter = end; auto iter = end;
if(end_tabs >= 0) { if(auto end_tabs = get_tabs(end)) {
bool can_select_end_block = false; bool can_select_end_block = false;
while(iter.forward_char()) { while(iter.forward_char()) {
auto tabs = get_tabs(iter); 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()) if(!iter.ends_line())
iter.forward_to_line_end(); iter.forward_to_line_end();
end = iter; end = iter;
if(tabs > end_tabs) if(tabs > end_tabs)
can_select_end_block = true; can_select_end_block = true;
if(tabs == end_tabs) else if(tabs == end_tabs)
break; break;
continue; continue;
} }
@ -3072,7 +3069,7 @@ bool Source::View::on_key_press_event_smart_inserts(GdkEventKey *key) {
} }
} }
// Insert '' // 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("''"); get_buffer()->insert_at_cursor("''");
auto iter = get_buffer()->get_insert()->get_iter(); auto iter = get_buffer()->get_insert()->get_iter();
iter.backward_char(); iter.backward_char();
@ -3081,7 +3078,7 @@ bool Source::View::on_key_press_event_smart_inserts(GdkEventKey *key) {
return true; return true;
} }
// Insert "" // 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("\"\""); get_buffer()->insert_at_cursor("\"\"");
auto iter = get_buffer()->get_insert()->get_iter(); auto iter = get_buffer()->get_insert()->get_iter();
iter.backward_char(); iter.backward_char();

2
src/source.hpp

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

7
src/source_base.hpp

@ -3,6 +3,7 @@
#include "mutex.hpp" #include "mutex.hpp"
#include "snippets.hpp" #include "snippets.hpp"
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/optional.hpp>
#include <gtksourceviewmm.h> #include <gtksourceviewmm.h>
#include <list> #include <list>
#include <regex> #include <regex>
@ -96,9 +97,9 @@ namespace Source {
bool keep_clipboard = false; bool keep_clipboard = false;
protected: protected:
std::time_t last_write_time; boost::optional<std::time_t> last_write_time;
void monitor_file(); 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; bool is_bracket_language = false;
@ -148,7 +149,7 @@ namespace Source {
std::vector<ExtraCursor> extra_cursors; std::vector<ExtraCursor> extra_cursors;
struct ExtraSnippetCursor { struct ExtraSnippetCursor {
Glib::RefPtr<Gtk::TextBuffer::Mark> mark; 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); 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() { void LanguageProtocol::Client::parse_server_message() {
if(!header_read) { if(!header_read) {
server_message_size = static_cast<size_t>(-1);
server_message_stream.seekg(0, std::ios::beg);
std::string line; std::string line;
while(!header_read && std::getline(server_message_stream, line)) { while(!header_read && std::getline(server_message_stream, line)) {
if(!line.empty() && line != "\r") { 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_content_pos = server_message_stream.tellg();
server_message_size += server_message_content_pos; *server_message_size += server_message_content_pos;
header_read = true; header_read = true;
} }
} }
@ -215,11 +212,11 @@ void LanguageProtocol::Client::parse_server_message() {
server_message_stream.seekg(0, std::ios::end); server_message_stream.seekg(0, std::ios::end);
size_t read_size = server_message_stream.tellg(); size_t read_size = server_message_stream.tellg();
std::stringstream tmp; std::stringstream tmp;
if(read_size >= server_message_size) { if(read_size >= *server_message_size) {
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.seekg(*server_message_size, std::ios::beg);
server_message_stream.seekp(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) { for(size_t c = *server_message_size; c < read_size; ++c) {
tmp.put(server_message_stream.get()); tmp.put(server_message_stream.get());
server_message_stream.put(' '); server_message_stream.put(' ');
} }
@ -279,13 +276,13 @@ void LanguageProtocol::Client::parse_server_message() {
} }
server_message_stream = std::stringstream(); server_message_stream = std::stringstream();
server_message_size.reset();
header_read = false; header_read = false;
server_message_size = static_cast<size_t>(-1);
tmp.seekg(0, std::ios::end); tmp.seekg(0, std::ios::end);
if(tmp.tellg() > 0) { if(tmp.tellg() > 0) {
tmp.seekg(0, std::ios::beg); server_message_stream = std::move(tmp);
server_message_stream << tmp.rdbuf(); server_message_stream.seekg(0, std::ios::beg);
parse_server_message(); parse_server_message();
} }
} }

3
src/source_language_protocol.hpp

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

44
src/terminal.cpp

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

8
src/terminal.hpp

@ -4,6 +4,7 @@
#include "process.hpp" #include "process.hpp"
#include "source_base.hpp" #include "source_base.hpp"
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/optional.hpp>
#include <functional> #include <functional>
#include <gtkmm.h> #include <gtkmm.h>
#include <iostream> #include <iostream>
@ -45,7 +46,12 @@ private:
Glib::RefPtr<Gdk::Cursor> default_mouse_cursor; Glib::RefPtr<Gdk::Cursor> default_mouse_cursor;
size_t deleted_lines = 0; 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); void apply_link_tags(const Gtk::TextIter &start_iter, const Gtk::TextIter &end_iter);
Mutex processes_mutex; 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; 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 // Keep tooltip if mouse is moving towards it
// Calculated using dot product between the mouse_pos vector and the corners of the tooltip window // 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; 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); 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_x = mouse_pos->first - last_mouse_pos->first;
int diff_y = mouse_pos.second - last_mouse_pos.second; int diff_y = mouse_pos->second - last_mouse_pos->second;
class Corner { class Corner {
public: public:
Corner(int x, int y) : x(x - root_x), y(y - root_y) {} 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)) if(rectangle.intersects(tooltip.activation_rectangle))
tooltip.show(disregard_drawn, on_motion); tooltip.show(disregard_drawn, on_motion);
else 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) for(auto &tooltip : tooltip_list)
tooltip.hide(last_mouse_pos, mouse_pos); tooltip.hide(last_mouse_pos, mouse_pos);
} }

5
src/tooltips.hpp

@ -1,4 +1,5 @@
#pragma once #pragma once
#include <boost/optional.hpp>
#include <functional> #include <functional>
#include <gtkmm.h> #include <gtkmm.h>
#include <list> #include <list>
@ -14,7 +15,7 @@ public:
void update(); void update();
void show(bool disregard_drawn = false, const std::function<void()> &on_motion = nullptr); 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; Gdk::Rectangle activation_rectangle;
Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark; Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark;
@ -61,7 +62,7 @@ public:
void show(const Gdk::Rectangle &rectangle, bool disregard_drawn = false); void show(const Gdk::Rectangle &rectangle, bool disregard_drawn = false);
void show(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(); }; void clear() { tooltip_list.clear(); };
template <typename... Ts> 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."); auto link = Terminal::get().find_link("~/test/test.cc:7:41: error: expected ';' after expression.");
assert(std::get<0>(link) == 0); assert(link);
assert(std::get<1>(link) == 19); assert(link->start_pos == 0);
assert(std::get<2>(link) == "~/test/test.cc"); assert(link->end_pos == 19);
assert(std::get<3>(link) == "7"); assert(link->path == "~/test/test.cc");
assert(std::get<4>(link) == "41"); 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."); auto link = Terminal::get().find_link("Assertion failed: (false), function main, file ~/test/test.cc, line 15.");
assert(std::get<0>(link) == 47); assert(link);
assert(std::get<1>(link) == 70); assert(link->start_pos == 47);
assert(std::get<2>(link) == "~/test/test.cc"); assert(link->end_pos == 70);
assert(std::get<3>(link) == "15"); 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."); 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(link);
assert(std::get<1>(link) == 28); assert(link->start_pos == 6);
assert(std::get<2>(link) == "~/examples/main.cpp"); assert(link->end_pos == 28);
assert(std::get<3>(link) == "17"); 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)"); auto link = Terminal::get().find_link("ERROR:~/test/test.cc:36:int main(): assertion failed: (false)");
assert(std::get<0>(link) == 6); assert(link);
assert(std::get<1>(link) == 23); assert(link->start_pos == 6);
assert(std::get<2>(link) == "~/test/test.cc"); assert(link->end_pos == 23);
assert(std::get<3>(link) == "36"); assert(link->path == "~/test/test.cc");
assert(link->line == 36);
assert(link->line_index == 1);
} }
} }

Loading…
Cancel
Save