Browse Source

Improved resource use of Terminal::print

pipelines/235045657
eidheim 5 years ago
parent
commit
6e485514ed
  1. 2
      src/juci.cpp
  2. 4
      src/project.cpp
  3. 163
      src/terminal.cpp
  4. 8
      src/terminal.hpp
  5. 7
      src/utility.cpp
  6. 2
      src/utility.hpp

2
src/juci.cpp

@ -98,7 +98,7 @@ void Application::on_activate() {
} }
for(auto &error : errors) for(auto &error : errors)
Terminal::get().print(error, true); Terminal::get().print(std::move(error), true);
if(!current_file.empty()) { if(!current_file.empty()) {
if(Notebook::get().open(current_file)) { if(Notebook::get().open(current_file)) {

4
src/project.cpp

@ -651,8 +651,8 @@ void Project::LLDB::debug_show_variables() {
void Project::LLDB::debug_run_command(const std::string &command) { void Project::LLDB::debug_run_command(const std::string &command) {
if(debugging) { if(debugging) {
auto command_return = Debug::LLDB::get().run_command(command); auto command_return = Debug::LLDB::get().run_command(command);
Terminal::get().async_print(command_return.first); Terminal::get().async_print(std::move(command_return.first));
Terminal::get().async_print(command_return.second, true); Terminal::get().async_print(std::move(command_return.second), true);
} }
} }

163
src/terminal.cpp

@ -4,6 +4,7 @@
#include "info.hpp" #include "info.hpp"
#include "notebook.hpp" #include "notebook.hpp"
#include "project.hpp" #include "project.hpp"
#include "utility.hpp"
#include <iostream> #include <iostream>
#include <regex> #include <regex>
#include <thread> #include <thread>
@ -21,6 +22,57 @@ Terminal::Terminal() : Source::SearchView() {
link_mouse_cursor = Gdk::Cursor::create(Gdk::CursorType::HAND1); link_mouse_cursor = Gdk::Cursor::create(Gdk::CursorType::HAND1);
default_mouse_cursor = Gdk::Cursor::create(Gdk::CursorType::XTERM); default_mouse_cursor = Gdk::Cursor::create(Gdk::CursorType::XTERM);
// Apply link tags
get_buffer()->signal_insert().connect([this](const Gtk::TextIter &iter, const Glib::ustring &text, int /*bytes*/) {
std::string line_start;
size_t line_start_pos = 0;
bool delimiter_found = false;
bool dot_found = false;
bool number_found = false;
auto start = iter;
start.backward_chars(text.size());
int line_nr = start.get_line();
auto parse_text = [&](const std::string &text) {
for(size_t i = 0; i < text.size(); ++i) {
if(text[i] == '\n') {
if(delimiter_found && dot_found && number_found) {
if(auto link = !line_start.empty()
? find_link(line_start + text, line_start_pos, (i + line_start.size()) - line_start_pos)
: find_link(text, line_start_pos, i - line_start_pos)) {
auto link_start = get_buffer()->get_iter_at_line(line_nr);
auto link_end = link_start;
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_pos = i + 1;
delimiter_found = false;
dot_found = false;
number_found = false;
++line_nr;
line_start.clear();
}
else if(text[i] == '/' || text[i] == '\\')
delimiter_found = true;
else if(text[i] == '.')
dot_found = true;
else if(text[i] >= '0' && text[i] <= '9')
number_found = true;
}
};
if(!start.starts_line()) {
auto end = start;
start = get_buffer()->get_iter_at_line(start.get_line());
line_start = get_buffer()->get_text(start, end).raw();
parse_text(line_start);
}
parse_text(text.raw());
});
} }
int Terminal::process(const std::string &command, const boost::filesystem::path &path, bool use_pipes) { int Terminal::process(const std::string &command, const boost::filesystem::path &path, bool use_pipes) {
@ -165,8 +217,10 @@ bool Terminal::on_motion_notify_event(GdkEventMotion *event) {
return Gtk::TextView::on_motion_notify_event(event); return Gtk::TextView::on_motion_notify_event(event);
} }
boost::optional<Terminal::Link> Terminal::find_link(const std::string &line) { boost::optional<Terminal::Link> Terminal::find_link(const std::string &line, size_t pos, size_t length) {
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
"^In file included from ([A-Z]:)?([^:]+):([0-9]+)[:,]$|" // C/C++ extra compile warning/error info
"^ from ([A-Z]:)?([^:]+):([0-9]+)[:,]$|" // C/C++ extra compile warning/error info (gcc)
"^ --> ([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()
"^[^:]*: ([A-Z]:)?([^:]+):([0-9]+): .* Assertion .* failed\\.$|" // gcc assert() "^[^:]*: ([A-Z]:)?([^:]+):([0-9]+): .* Assertion .* failed\\.$|" // gcc assert()
@ -174,12 +228,16 @@ boost::optional<Terminal::Link> Terminal::find_link(const std::string &line) {
"^([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
std::smatch sm; std::smatch sm;
if(std::regex_match(line, sm, link_regex)) { if(std::regex_match(line.cbegin() + pos,
line.cbegin() + (length == std::string::npos ? line.size() : std::min(pos + length, line.size())),
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 == 4 + 3 + 3 + 1 ? 4 : 3;
if(sm.length(sub + 1)) { if(sm.length(sub + 1)) {
auto start_pos = static_cast<int>(sm.position(sub + 1) - sm.length(sub)); 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)); auto end_pos = static_cast<int>(sm.position(sub + subs - 1) + sm.length(sub + subs - 1));
int start_pos_utf8 = utf8_character_count(line, 0, start_pos);
int end_pos_utf8 = start_pos_utf8 + utf8_character_count(line, start_pos, end_pos - start_pos);
std::string path; std::string path;
if(sm.length(sub)) if(sm.length(sub))
path = sm[sub].str(); path = sm[sub].str();
@ -187,7 +245,7 @@ boost::optional<Terminal::Link> Terminal::find_link(const std::string &line) {
try { try {
auto line_number = std::stoi(sm[sub + 2].str()); auto line_number = std::stoi(sm[sub + 2].str());
auto line_offset = std::stoi(subs == 4 ? sm[sub + 3].str() : "1"); auto line_offset = std::stoi(subs == 4 ? sm[sub + 3].str() : "1");
return Link{start_pos, end_pos, path, line_number, line_offset}; return Link{start_pos_utf8, end_pos_utf8, path, line_number, line_offset};
} }
catch(...) { catch(...) {
return {}; return {};
@ -199,62 +257,20 @@ boost::optional<Terminal::Link> Terminal::find_link(const std::string &line) {
return {}; return {};
} }
void Terminal::apply_link_tags(const Gtk::TextIter &start_iter, const Gtk::TextIter &end_iter) { void Terminal::print(std::string message, bool bold) {
auto iter = start_iter;
Gtk::TextIter line_start;
bool line_start_set = false;
bool delimiter_found = false;
bool dot_found = false;
bool number_found = false;
do {
if(iter.starts_line()) {
line_start = iter;
line_start_set = true;
delimiter_found = false;
dot_found = false;
number_found = false;
}
if(line_start_set && (*iter == '\\' || *iter == '/'))
delimiter_found = true;
else if(line_start_set && *iter == '.')
dot_found = true;
else if(line_start_set && (*iter >= '0' && *iter <= '9'))
number_found = true;
else if(line_start_set && delimiter_found && dot_found && number_found && iter.ends_line()) {
auto line = get_buffer()->get_text(line_start, iter);
//Convert to ascii for std::regex and Gtk::Iter::forward_chars
for(size_t c = 0; c < line.size(); ++c) {
if(line[c] > 127)
line.replace(c, 1, "a");
}
auto link = find_link(line.raw());
if(link) {
auto link_start = line_start;
auto link_end = line_start;
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;
}
} while(iter.forward_char() && iter != end_iter);
}
size_t Terminal::print(const std::string &message, bool bold) {
#ifdef _WIN32 #ifdef _WIN32
//Remove color codes // Remove color codes
auto message_no_color = message; //copy here since operations on Glib::ustring is too slow
size_t pos = 0; size_t pos = 0;
while((pos = message_no_color.find('\e', pos)) != std::string::npos) { while((pos = message.find('\e', pos)) != std::string::npos) {
if((pos + 2) >= message_no_color.size()) if((pos + 2) >= message.size())
break; break;
if(message_no_color[pos + 1] == '[') { if(message[pos + 1] == '[') {
size_t end_pos = pos + 2; size_t end_pos = pos + 2;
bool color_code_found = false; bool color_code_found = false;
while(end_pos < message_no_color.size()) { while(end_pos < message.size()) {
if((message_no_color[end_pos] >= '0' && message_no_color[end_pos] <= '9') || message_no_color[end_pos] == ';') if((message[end_pos] >= '0' && message[end_pos] <= '9') || message[end_pos] == ';')
end_pos++; end_pos++;
else if(message_no_color[end_pos] == 'm') { else if(message[end_pos] == 'm') {
color_code_found = true; color_code_found = true;
break; break;
} }
@ -262,12 +278,12 @@ size_t Terminal::print(const std::string &message, bool bold) {
break; break;
} }
if(color_code_found) if(color_code_found)
message_no_color.erase(pos, end_pos - pos + 1); message.erase(pos, end_pos - pos + 1);
} }
} }
Glib::ustring umessage = message_no_color; Glib::ustring umessage = std::move(message);
#else #else
Glib::ustring umessage = message; Glib::ustring umessage = std::move(message);
#endif #endif
Glib::ustring::iterator iter; Glib::ustring::iterator iter;
@ -277,48 +293,21 @@ size_t Terminal::print(const std::string &message, bool bold) {
umessage.replace(iter, next_char_iter, "?"); umessage.replace(iter, next_char_iter, "?");
} }
Source::Mark start_mark(get_buffer()->get_iter_at_line(get_buffer()->end().get_line()));
if(bold) if(bold)
get_buffer()->insert_with_tag(get_buffer()->end(), umessage, bold_tag); get_buffer()->insert_with_tag(get_buffer()->end(), umessage, bold_tag);
else else
get_buffer()->insert(get_buffer()->end(), umessage); get_buffer()->insert(get_buffer()->end(), umessage);
auto start_iter = start_mark->get_iter();
auto end_iter = get_buffer()->get_insert()->get_iter();
apply_link_tags(start_iter, end_iter);
if(get_buffer()->get_line_count() > Config::get().terminal.history_size) { if(get_buffer()->get_line_count() > Config::get().terminal.history_size) {
int lines = get_buffer()->get_line_count() - Config::get().terminal.history_size; int lines = get_buffer()->get_line_count() - Config::get().terminal.history_size;
get_buffer()->erase(get_buffer()->begin(), get_buffer()->get_iter_at_line(lines)); get_buffer()->erase(get_buffer()->begin(), get_buffer()->get_iter_at_line(lines));
deleted_lines += static_cast<size_t>(lines); deleted_lines += static_cast<size_t>(lines);
} }
return static_cast<size_t>(get_buffer()->end().get_line()) + deleted_lines;
} }
void Terminal::async_print(const std::string &message, bool bold) { void Terminal::async_print(std::string message, bool bold) {
dispatcher.post([message, bold] { dispatcher.post([message = std::move(message), bold]() mutable {
Terminal::get().print(message, bold); Terminal::get().print(std::move(message), bold);
});
}
void Terminal::async_print(size_t line_nr, const std::string &message) {
dispatcher.post([this, line_nr, message] {
if(line_nr < deleted_lines)
return;
Glib::ustring umessage = message;
Glib::ustring::iterator iter;
while(!umessage.validate(iter)) {
auto next_char_iter = iter;
next_char_iter++;
umessage.replace(iter, next_char_iter, "?");
}
auto end_line_iter = get_buffer()->get_iter_at_line(static_cast<int>(line_nr - deleted_lines));
while(!end_line_iter.ends_line() && end_line_iter.forward_char()) {
}
get_buffer()->insert(end_line_iter, umessage);
}); });
} }

8
src/terminal.hpp

@ -25,9 +25,8 @@ public:
void kill_last_async_process(bool force = false); void kill_last_async_process(bool force = false);
void kill_async_processes(bool force = false); void kill_async_processes(bool force = false);
size_t print(const std::string &message, bool bold = false); void print(std::string message, bool bold = false);
void async_print(const std::string &message, bool bold = false); void async_print(std::string message, bool bold = false);
void async_print(size_t line_nr, const std::string &message);
void configure(); void configure();
@ -51,8 +50,7 @@ private:
std::string path; std::string path;
int line, line_index; int line, line_index;
}; };
boost::optional<Link> find_link(const std::string &line); boost::optional<Link> find_link(const std::string &line, size_t pos = 0, size_t length = std::string::npos);
void apply_link_tags(const Gtk::TextIter &start_iter, const Gtk::TextIter &end_iter);
Mutex processes_mutex; Mutex processes_mutex;
std::vector<std::shared_ptr<TinyProcessLib::Process>> processes GUARDED_BY(processes_mutex); std::vector<std::shared_ptr<TinyProcessLib::Process>> processes GUARDED_BY(processes_mutex);

7
src/utility.cpp

@ -6,10 +6,11 @@ ScopeGuard::~ScopeGuard() {
on_exit(); on_exit();
} }
size_t utf8_character_count(const std::string &text) noexcept { size_t utf8_character_count(const std::string &text, size_t pos, size_t length) noexcept {
size_t count = 0; size_t count = 0;
for(auto chr : text) { auto size = length == std::string::npos ? text.size() : std::min(pos + length, text.size());
if(static_cast<unsigned char>(chr) <= 0b01111111 || static_cast<unsigned char>(chr) >= 0b11000000) for(; pos < size; ++pos) {
if(static_cast<unsigned char>(text[pos]) <= 0b01111111 || static_cast<unsigned char>(text[pos]) >= 0b11000000)
++count; ++count;
} }
return count; return count;

2
src/utility.hpp

@ -9,7 +9,7 @@ public:
}; };
/// Returns number of utf8 characters in text argument /// Returns number of utf8 characters in text argument
size_t utf8_character_count(const std::string &text) noexcept; size_t utf8_character_count(const std::string &text, size_t pos = 0, size_t length = std::string::npos) noexcept;
bool starts_with(const char *str, const std::string &test) noexcept; bool starts_with(const char *str, const std::string &test) noexcept;
bool starts_with(const char *str, const char *test) noexcept; bool starts_with(const char *str, const char *test) noexcept;

Loading…
Cancel
Save