Browse Source

Cleanup of ANSI escape code parsing, and added support for bold, italic, underline and strikethrough codes

master
eidheim 2 months ago
parent
commit
aa697b3ad8
  1. 4
      src/notebook.cpp
  2. 36
      src/project.cpp
  3. 173
      src/terminal.cpp
  4. 4
      src/terminal.hpp
  5. 16
      src/window.cpp
  6. 78
      tests/terminal_test.cpp

4
src/notebook.cpp

@ -254,7 +254,7 @@ bool Notebook::open(const boost::filesystem::path &file_path_, Position position
}); });
boost::optional<int> exit_status; boost::optional<int> exit_status;
std::string command = "rustup component add rust-analyzer"; std::string command = "rustup component add rust-analyzer";
Terminal::get().print("\e[2mRunning: " + command + "\e[m\n"); Terminal::get().print("\e[37mRunning: " + command + "\e[m\n");
auto process = Terminal::get().async_process(command, "", [&exit_status](int exit_status_) { auto process = Terminal::get().async_process(command, "", [&exit_status](int exit_status_) {
exit_status = exit_status_; exit_status = exit_status_;
}); });
@ -627,7 +627,7 @@ void Notebook::install_rust() {
}); });
boost::optional<int> exit_status; boost::optional<int> exit_status;
std::string command = "curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y"; std::string command = "curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y";
Terminal::get().print("\e[2mRunning: " + command + "\e[m\n"); Terminal::get().print("\e[37mRunning: " + command + "\e[m\n");
auto process = Terminal::get().async_process(command, "", [&exit_status](int exit_status_) { auto process = Terminal::get().async_process(command, "", [&exit_status](int exit_status_) {
exit_status = exit_status_; exit_status = exit_status_;
}); });

36
src/project.cpp

@ -397,7 +397,7 @@ void Project::LLDB::debug_compile_and_start() {
if(Config::get().terminal.clear_on_compile) if(Config::get().terminal.clear_on_compile)
Terminal::get().clear(); Terminal::get().clear();
Terminal::get().print("\e[2mCompiling and debugging: " + run_arguments + "\e[m\n"); Terminal::get().print("\e[37mCompiling and debugging: " + run_arguments + "\e[m\n");
Terminal::get().async_process(build->get_compile_command(), debug_build_path, [self = shared_from_this(), debug_build_path, run_arguments, project_path = build->project_path, remote_host](int exit_status) { Terminal::get().async_process(build->get_compile_command(), debug_build_path, [self = shared_from_this(), debug_build_path, run_arguments, project_path = build->project_path, remote_host](int exit_status) {
if(exit_status != 0) { if(exit_status != 0) {
debugging = false; debugging = false;
@ -428,7 +428,7 @@ void Project::LLDB::debug_start(const std::string &command, const boost::filesys
Debug::LLDB::get().on_exit.erase(on_exit_it); Debug::LLDB::get().on_exit.erase(on_exit_it);
Debug::LLDB::get().on_exit.emplace_back([self = shared_from_this(), command](int exit_status) { Debug::LLDB::get().on_exit.emplace_back([self = shared_from_this(), command](int exit_status) {
debugging = false; debugging = false;
Terminal::get().async_print("\e[2m" + command + " returned: " + (exit_status == 0 ? "\e[32m" : "\e[31m") + std::to_string(exit_status) + "\e[m\n"); Terminal::get().async_print("\e[37m" + command + " returned: " + (exit_status == 0 ? "\e[32m" : "\e[31m") + std::to_string(exit_status) + "\e[m\n");
self->dispatcher.post([] { self->dispatcher.post([] {
debug_update_status(""); debug_update_status("");
}); });
@ -728,7 +728,7 @@ void Project::Clang::compile() {
if(Config::get().terminal.clear_on_compile) if(Config::get().terminal.clear_on_compile)
Terminal::get().clear(); Terminal::get().clear();
Terminal::get().print("\e[2mCompiling project: " + filesystem::get_short_path(build->project_path).string() + "\e[m\n"); Terminal::get().print("\e[37mCompiling project: " + filesystem::get_short_path(build->project_path).string() + "\e[m\n");
Terminal::get().async_process(build->get_compile_command(), default_build_path, [self = shared_from_this(), default_build_path](int exit_status) { Terminal::get().async_process(build->get_compile_command(), default_build_path, [self = shared_from_this(), default_build_path](int exit_status) {
compiling = false; compiling = false;
if(exit_status != 0 && !self->build->is_valid(default_build_path)) if(exit_status != 0 && !self->build->is_valid(default_build_path))
@ -773,12 +773,12 @@ void Project::Clang::compile_and_run(const boost::filesystem::path &file_path) {
if(Config::get().terminal.clear_on_compile) if(Config::get().terminal.clear_on_compile)
Terminal::get().clear(); Terminal::get().clear();
Terminal::get().print("\e[2mCompiling and running: " + arguments + "\e[m\n"); Terminal::get().print("\e[37mCompiling and running: " + arguments + "\e[m\n");
Terminal::get().async_process(build->get_compile_command(), default_build_path, [self = shared_from_this(), arguments, project_path, default_build_path](int exit_status) { Terminal::get().async_process(build->get_compile_command(), default_build_path, [self = shared_from_this(), arguments, project_path, default_build_path](int exit_status) {
compiling = false; compiling = false;
if(exit_status == 0) { if(exit_status == 0) {
Terminal::get().async_process(arguments, project_path, [arguments](int exit_status) { Terminal::get().async_process(arguments, project_path, [arguments](int exit_status) {
Terminal::get().print("\e[2m" + arguments + " returned: " + (exit_status == 0 ? "\e[32m" : "\e[31m") + std::to_string(exit_status) + "\e[m\n"); Terminal::get().print("\e[37m" + arguments + " returned: " + (exit_status == 0 ? "\e[32m" : "\e[31m") + std::to_string(exit_status) + "\e[m\n");
}); });
} }
else if(!self->build->is_valid(default_build_path)) else if(!self->build->is_valid(default_build_path))
@ -896,9 +896,9 @@ void Project::Python::compile_and_run(const boost::filesystem::path &file_path)
if(Config::get().terminal.clear_on_compile) if(Config::get().terminal.clear_on_compile)
Terminal::get().clear(); Terminal::get().clear();
Terminal::get().print("\e[2mRunning: " + command + "\e[m\n"); Terminal::get().print("\e[37mRunning: " + command + "\e[m\n");
Terminal::get().async_process(command, path, [command](int exit_status) { Terminal::get().async_process(command, path, [command](int exit_status) {
Terminal::get().print("\e[2m" + command + " returned: " + (exit_status == 0 ? "\e[32m" : "\e[31m") + std::to_string(exit_status) + "\e[m\n"); Terminal::get().print("\e[37m" + command + " returned: " + (exit_status == 0 ? "\e[32m" : "\e[31m") + std::to_string(exit_status) + "\e[m\n");
}); });
} }
@ -923,9 +923,9 @@ void Project::JavaScript::compile_and_run(const boost::filesystem::path &file_pa
if(Config::get().terminal.clear_on_compile) if(Config::get().terminal.clear_on_compile)
Terminal::get().clear(); Terminal::get().clear();
Terminal::get().print("\e[2mRunning: " + command + "\e[m\n"); Terminal::get().print("\e[37mRunning: " + command + "\e[m\n");
Terminal::get().async_process(command, path, [command](int exit_status) { Terminal::get().async_process(command, path, [command](int exit_status) {
Terminal::get().print("\e[2m" + command + " returned: " + (exit_status == 0 ? "\e[32m" : "\e[31m") + std::to_string(exit_status) + "\e[m\n"); Terminal::get().print("\e[37m" + command + " returned: " + (exit_status == 0 ? "\e[32m" : "\e[31m") + std::to_string(exit_status) + "\e[m\n");
}); });
} }
@ -936,9 +936,9 @@ void Project::HTML::compile_and_run(const boost::filesystem::path &file_path) {
if(Config::get().terminal.clear_on_compile) if(Config::get().terminal.clear_on_compile)
Terminal::get().clear(); Terminal::get().clear();
Terminal::get().print("\e[2mRunning: " + command + "\e[m\n"); Terminal::get().print("\e[37mRunning: " + command + "\e[m\n");
Terminal::get().async_process(command, build->project_path, [command](int exit_status) { Terminal::get().async_process(command, build->project_path, [command](int exit_status) {
Terminal::get().print("\e[2m" + command + " returned: " + (exit_status == 0 ? "\e[32m" : "\e[31m") + std::to_string(exit_status) + "\e[m\n"); Terminal::get().print("\e[37m" + command + " returned: " + (exit_status == 0 ? "\e[32m" : "\e[31m") + std::to_string(exit_status) + "\e[m\n");
}); });
} }
else if(!file_path.empty()) else if(!file_path.empty())
@ -966,7 +966,7 @@ void Project::Rust::compile() {
if(Config::get().terminal.clear_on_compile) if(Config::get().terminal.clear_on_compile)
Terminal::get().clear(); Terminal::get().clear();
Terminal::get().print("\e[2mCompiling project: " + filesystem::get_short_path(build->project_path).string() + "\e[m\n"); Terminal::get().print("\e[37mCompiling project: " + filesystem::get_short_path(build->project_path).string() + "\e[m\n");
Terminal::get().async_process(build->get_compile_command(), build->project_path, [](int exit_status) { Terminal::get().async_process(build->get_compile_command(), build->project_path, [](int exit_status) {
compiling = false; compiling = false;
@ -980,14 +980,14 @@ void Project::Rust::compile_and_run(const boost::filesystem::path &file_path) {
Terminal::get().clear(); Terminal::get().clear();
auto arguments = get_run_arguments().second; auto arguments = get_run_arguments().second;
Terminal::get().print("\e[2mCompiling and running: " + arguments + "\e[m\n"); Terminal::get().print("\e[37mCompiling and running: " + arguments + "\e[m\n");
auto self = this->shared_from_this(); auto self = this->shared_from_this();
Terminal::get().async_process(build->get_compile_command(), build->project_path, [self, arguments = std::move(arguments)](int exit_status) { Terminal::get().async_process(build->get_compile_command(), build->project_path, [self, arguments = std::move(arguments)](int exit_status) {
compiling = false; compiling = false;
if(exit_status == 0) { if(exit_status == 0) {
Terminal::get().async_process(arguments, self->build->project_path, [arguments](int exit_status) { Terminal::get().async_process(arguments, self->build->project_path, [arguments](int exit_status) {
Terminal::get().print("\e[2m" + arguments + " returned: " + (exit_status == 0 ? "\e[32m" : "\e[31m") + std::to_string(exit_status) + "\e[m\n"); Terminal::get().print("\e[37m" + arguments + " returned: " + (exit_status == 0 ? "\e[32m" : "\e[31m") + std::to_string(exit_status) + "\e[m\n");
}); });
} }
}); });
@ -1014,9 +1014,9 @@ void Project::Go::compile_and_run(const boost::filesystem::path &file_path) {
if(Config::get().terminal.clear_on_compile) if(Config::get().terminal.clear_on_compile)
Terminal::get().clear(); Terminal::get().clear();
Terminal::get().print("\e[2mRunning: " + command + "\e[m\n"); Terminal::get().print("\e[37mRunning: " + command + "\e[m\n");
Terminal::get().async_process(command, path, [command](int exit_status) { Terminal::get().async_process(command, path, [command](int exit_status) {
Terminal::get().print("\e[2m" + command + " returned: " + (exit_status == 0 ? "\e[32m" : "\e[31m") + std::to_string(exit_status) + "\e[m\n"); Terminal::get().print("\e[37m" + command + " returned: " + (exit_status == 0 ? "\e[32m" : "\e[31m") + std::to_string(exit_status) + "\e[m\n");
}); });
} }
@ -1037,8 +1037,8 @@ void Project::Julia::compile_and_run(const boost::filesystem::path &file_path) {
if(Config::get().terminal.clear_on_compile) if(Config::get().terminal.clear_on_compile)
Terminal::get().clear(); Terminal::get().clear();
Terminal::get().print("\e[2mRunning: " + command + "\e[m\n"); Terminal::get().print("\e[37mRunning: " + command + "\e[m\n");
Terminal::get().async_process(command, path, [command](int exit_status) { Terminal::get().async_process(command, path, [command](int exit_status) {
Terminal::get().print("\e[2m" + command + " returned: " + (exit_status == 0 ? "\e[32m" : "\e[31m") + std::to_string(exit_status) + "\e[m\n"); Terminal::get().print("\e[37m" + command + " returned: " + (exit_status == 0 ? "\e[32m" : "\e[31m") + std::to_string(exit_status) + "\e[m\n");
}); });
} }

173
src/terminal.cpp

@ -17,6 +17,15 @@ Terminal::Terminal() : Source::CommonView() {
bold_tag = get_buffer()->create_tag(); bold_tag = get_buffer()->create_tag();
bold_tag->property_weight() = Pango::WEIGHT_BOLD; bold_tag->property_weight() = Pango::WEIGHT_BOLD;
light_tag = get_buffer()->create_tag();
light_tag->property_weight() = Pango::WEIGHT_LIGHT;
italic_tag = get_buffer()->create_tag();
italic_tag->property_style() = Pango::STYLE_ITALIC;
underline_tag = get_buffer()->create_tag();
underline_tag->property_underline() = Pango::Underline::UNDERLINE_SINGLE;
strikethrough_tag = get_buffer()->create_tag();
strikethrough_tag->property_strikethrough() = true;
red_tag = get_buffer()->create_tag(); red_tag = get_buffer()->create_tag();
green_tag = get_buffer()->create_tag(); green_tag = get_buffer()->create_tag();
@ -24,7 +33,7 @@ Terminal::Terminal() : Source::CommonView() {
blue_tag = get_buffer()->create_tag(); blue_tag = get_buffer()->create_tag();
magenta_tag = get_buffer()->create_tag(); magenta_tag = get_buffer()->create_tag();
cyan_tag = get_buffer()->create_tag(); cyan_tag = get_buffer()->create_tag();
gray_tag = get_buffer()->create_tag(); white_tag = get_buffer()->create_tag();
link_tag = get_buffer()->create_tag(); link_tag = get_buffer()->create_tag();
link_tag->property_underline() = Pango::Underline::UNDERLINE_SINGLE; link_tag->property_underline() = Pango::Underline::UNDERLINE_SINGLE;
@ -110,7 +119,38 @@ Terminal::Terminal() : Source::CommonView() {
return {}; return {};
} }
}; };
get_buffer()->signal_insert().connect([this, detect_possible_link = DetectPossibleLink(), parse_ansi_escape_sequence = ParseAnsiEscapeSequence(), last_color = -1, last_color_sequence_mark = std::shared_ptr<Source::Mark>()](const Gtk::TextIter &iter, const Glib::ustring &text_, int /*bytes*/) mutable { class Code {
public:
int code = -1;
std::shared_ptr<Source::Mark> start_mark;
};
auto code_to_color_tag = [this](int code) {
if(code == 31)
return red_tag;
else if(code == 32)
return green_tag;
else if(code == 33)
return yellow_tag;
else if(code == 34)
return blue_tag;
else if(code == 35)
return magenta_tag;
else if(code == 36)
return cyan_tag;
else if(code == 37)
return white_tag;
return Glib::RefPtr<Gtk::TextTag>();
};
auto code_to_weight_tag = [this](int code) {
if(code == 1)
return bold_tag;
else if(code == 2)
return light_tag;
return Glib::RefPtr<Gtk::TextTag>();
};
get_buffer()->signal_insert().connect([this, code_to_color_tag, code_to_weight_tag,
detect_possible_link = DetectPossibleLink(), parse_ansi_escape_sequence = ParseAnsiEscapeSequence(),
color_code = Code(), weight_code = Code(), italic_code = Code(), underline_code = Code(), strikethrough_code = Code()](const Gtk::TextIter &iter, const Glib::ustring &text_, int /*bytes*/) mutable {
boost::optional<Gtk::TextIter> start_of_text; boost::optional<Gtk::TextIter> start_of_text;
int line_nr_offset = 0; int line_nr_offset = 0;
auto get_line_nr = [&] { auto get_line_nr = [&] {
@ -144,9 +184,31 @@ Terminal::Terminal() : Source::CommonView() {
start.backward_chars(sequence->length); start.backward_chars(sequence->length);
get_buffer()->apply_tag(invisible_tag, start, end); get_buffer()->apply_tag(invisible_tag, start, end);
if(sequence->command == 'm') { if(sequence->command == 'm') {
int color = -1; auto reset = [&] {
if(sequence->arguments.empty()) if(color_code.start_mark) {
color = 0; auto tag = code_to_color_tag(color_code.code);
if(tag)
get_buffer()->apply_tag(tag, (*color_code.start_mark)->get_iter(), start);
}
if(weight_code.start_mark) {
auto tag = code_to_weight_tag(weight_code.code);
if(tag)
get_buffer()->apply_tag(tag, (*weight_code.start_mark)->get_iter(), start);
}
if(italic_code.start_mark)
get_buffer()->apply_tag(italic_tag, (*italic_code.start_mark)->get_iter(), start);
if(underline_code.start_mark)
get_buffer()->apply_tag(underline_tag, (*underline_code.start_mark)->get_iter(), start);
if(strikethrough_code.start_mark)
get_buffer()->apply_tag(strikethrough_tag, (*strikethrough_code.start_mark)->get_iter(), start);
color_code = {};
weight_code = {};
italic_code = {};
underline_code = {};
strikethrough_code = {};
};
if(sequence->arguments.empty()) // Reset
reset();
else { else {
size_t pos = 0; size_t pos = 0;
size_t start_pos = pos; size_t start_pos = pos;
@ -154,16 +216,74 @@ Terminal::Terminal() : Source::CommonView() {
pos = sequence->arguments.find(";", pos); pos = sequence->arguments.find(";", pos);
try { try {
auto code = std::stoi(sequence->arguments.substr(start_pos, pos != std::string::npos ? pos - start_pos : pos)); auto code = std::stoi(sequence->arguments.substr(start_pos, pos != std::string::npos ? pos - start_pos : pos));
if(code == 39) if(code == 0) // Reset
color = 0; reset();
else if(code == 38) { else if(code == 1 || code == 2) { // Bold or faint
color = 0; if(weight_code.start_mark) {
break; // Do not read next arguments auto tag = code_to_weight_tag(weight_code.code);
if(tag)
get_buffer()->apply_tag(tag, (*weight_code.start_mark)->get_iter(), start);
}
weight_code = {code, std::make_shared<Source::Mark>(end)};
}
else if(code == 3) // Italic
italic_code = {code, std::make_shared<Source::Mark>(end)};
else if(code == 4) // Underline
underline_code = {code, std::make_shared<Source::Mark>(end)};
else if(code == 9) // Strikethrough
strikethrough_code = {code, std::make_shared<Source::Mark>(end)};
else if(code == 22) { // Normal intensity
if(weight_code.start_mark) {
auto tag = code_to_weight_tag(weight_code.code);
if(tag)
get_buffer()->apply_tag(tag, (*weight_code.start_mark)->get_iter(), start);
}
weight_code = {};
}
else if(code == 23) { // No italic
if(italic_code.start_mark)
get_buffer()->apply_tag(italic_tag, (*italic_code.start_mark)->get_iter(), start);
italic_code = {};
} }
else if(code == 48 || code == 58) else if(code == 24) { // No underline
break; // Do not read next arguments if(underline_code.start_mark)
else if(code == 0 || code == 2 || code == 22 || (code >= 30 && code <= 37)) get_buffer()->apply_tag(underline_tag, (*underline_code.start_mark)->get_iter(), start);
color = code; underline_code = {};
}
else if(code == 29) { // No strikethrough
if(strikethrough_code.start_mark)
get_buffer()->apply_tag(strikethrough_tag, (*strikethrough_code.start_mark)->get_iter(), start);
strikethrough_code = {};
}
else if(code >= 30 && code <= 37) { // Foreground color
if(color_code.start_mark) {
auto tag = code_to_color_tag(color_code.code);
if(tag)
get_buffer()->apply_tag(tag, (*color_code.start_mark)->get_iter(), start);
}
color_code = {code, std::make_shared<Source::Mark>(end)};
}
else if(code == 38) { // Set specific color not supported
if(color_code.start_mark) {
auto tag = code_to_color_tag(color_code.code);
if(tag)
get_buffer()->apply_tag(tag, (*color_code.start_mark)->get_iter(), start);
}
color_code = {};
break;
}
else if(code == 39) { // Default color
if(color_code.start_mark) {
auto tag = code_to_color_tag(color_code.code);
if(tag)
get_buffer()->apply_tag(tag, (*color_code.start_mark)->get_iter(), start);
}
color_code = {};
}
else if(code == 48) // Set specific background color not supported
break;
else if(code == 58) // Set specific underline color not supported
break;
} }
catch(...) { catch(...) {
} }
@ -173,27 +293,6 @@ Terminal::Terminal() : Source::CommonView() {
start_pos = pos; start_pos = pos;
} }
} }
if(last_color >= 0) {
if(last_color == 31)
get_buffer()->apply_tag(red_tag, (*last_color_sequence_mark)->get_iter(), start);
else if(last_color == 32)
get_buffer()->apply_tag(green_tag, (*last_color_sequence_mark)->get_iter(), start);
else if(last_color == 33)
get_buffer()->apply_tag(yellow_tag, (*last_color_sequence_mark)->get_iter(), start);
else if(last_color == 34)
get_buffer()->apply_tag(blue_tag, (*last_color_sequence_mark)->get_iter(), start);
else if(last_color == 35)
get_buffer()->apply_tag(magenta_tag, (*last_color_sequence_mark)->get_iter(), start);
else if(last_color == 36)
get_buffer()->apply_tag(cyan_tag, (*last_color_sequence_mark)->get_iter(), start);
else if(last_color == 37 || last_color == 2)
get_buffer()->apply_tag(gray_tag, (*last_color_sequence_mark)->get_iter(), start);
}
if(color >= 0) {
last_color = color;
last_color_sequence_mark = std::make_shared<Source::Mark>(end);
}
} }
} }
if(text[i] == '\n') if(text[i] == '\n')
@ -540,11 +639,11 @@ void Terminal::configure() {
cyan_tag->property_foreground_rgba() = rgba; cyan_tag->property_foreground_rgba() = rgba;
rgba.set_rgba(0.5, 0.5, 0.5); rgba.set_rgba(0.5, 0.5, 0.5);
factor = light_theme ? 0.6 : 0.4; factor = light_theme ? 0.7 : 0.4;
rgba.set_red(normal_color.get_red() + factor * (rgba.get_red() - normal_color.get_red())); rgba.set_red(normal_color.get_red() + factor * (rgba.get_red() - normal_color.get_red()));
rgba.set_green(normal_color.get_green() + factor * (rgba.get_green() - normal_color.get_green())); rgba.set_green(normal_color.get_green() + factor * (rgba.get_green() - normal_color.get_green()));
rgba.set_blue(normal_color.get_blue() + factor * (rgba.get_blue() - normal_color.get_blue())); rgba.set_blue(normal_color.get_blue() + factor * (rgba.get_blue() - normal_color.get_blue()));
gray_tag->property_foreground_rgba() = rgba; white_tag->property_foreground_rgba() = rgba;
// Set search match style: // Set search match style:
get_buffer()->get_tag_table()->foreach([](const Glib::RefPtr<Gtk::TextTag> &tag) { get_buffer()->get_tag_table()->foreach([](const Glib::RefPtr<Gtk::TextTag> &tag) {

4
src/terminal.hpp

@ -46,10 +46,10 @@ protected:
private: private:
Dispatcher dispatcher; Dispatcher dispatcher;
Glib::RefPtr<Gtk::TextTag> bold_tag; Glib::RefPtr<Gtk::TextTag> bold_tag, light_tag, italic_tag, underline_tag, strikethrough_tag;
Glib::RefPtr<Gtk::TextTag> link_tag; Glib::RefPtr<Gtk::TextTag> link_tag;
Glib::RefPtr<Gtk::TextTag> invisible_tag; Glib::RefPtr<Gtk::TextTag> invisible_tag;
Glib::RefPtr<Gtk::TextTag> red_tag, green_tag, yellow_tag, blue_tag, magenta_tag, cyan_tag, gray_tag; Glib::RefPtr<Gtk::TextTag> red_tag, green_tag, yellow_tag, blue_tag, magenta_tag, cyan_tag, white_tag;
Glib::RefPtr<Gdk::Cursor> link_mouse_cursor; Glib::RefPtr<Gdk::Cursor> link_mouse_cursor;
Glib::RefPtr<Gdk::Cursor> default_mouse_cursor; Glib::RefPtr<Gdk::Cursor> default_mouse_cursor;

16
src/window.cpp

@ -1453,10 +1453,10 @@ void Window::set_menu_actions() {
auto directory_folder = Project::get_preferably_directory_folder(); auto directory_folder = Project::get_preferably_directory_folder();
if(Config::get().terminal.clear_on_run_command) if(Config::get().terminal.clear_on_run_command)
Terminal::get().clear(); Terminal::get().clear();
Terminal::get().async_print("\e[2mRunning: " + content + "\e[m\n"); Terminal::get().async_print("\e[37mRunning: " + content + "\e[m\n");
Terminal::get().async_process(content, directory_folder, [content](int exit_status) { Terminal::get().async_process(content, directory_folder, [content](int exit_status) {
Terminal::get().print("\e[2m" + content + " returned: " + (exit_status == 0 ? "\e[32m" : "\e[31m") + std::to_string(exit_status) + "\e[m\n"); Terminal::get().print("\e[37m" + content + " returned: " + (exit_status == 0 ? "\e[32m" : "\e[31m") + std::to_string(exit_status) + "\e[m\n");
}); });
} }
if(Config::get().terminal.hide_entry_on_run_command) if(Config::get().terminal.hide_entry_on_run_command)
@ -1975,19 +1975,19 @@ bool Window::on_key_press_event(GdkEventKey *event) {
if(!command.debug) { if(!command.debug) {
Project::compiling = true; Project::compiling = true;
Terminal::get().print("\e[2mCompiling and running: " + label + "\e[m\n"); Terminal::get().print("\e[37mCompiling and running: " + label + "\e[m\n");
Terminal::get().async_process(compile, run_path, [run, run_path, label](int exit_status) { Terminal::get().async_process(compile, run_path, [run, run_path, label](int exit_status) {
Project::compiling = false; Project::compiling = false;
if(exit_status == 0) { if(exit_status == 0) {
Terminal::get().async_process(run, run_path, [label](int exit_status) { Terminal::get().async_process(run, run_path, [label](int exit_status) {
Terminal::get().print("\e[2m" + label + " returned: " + (exit_status == 0 ? "\e[32m" : "\e[31m") + std::to_string(exit_status) + "\e[m\n"); Terminal::get().print("\e[37m" + label + " returned: " + (exit_status == 0 ? "\e[32m" : "\e[31m") + std::to_string(exit_status) + "\e[m\n");
}); });
} }
}); });
} }
else { // Debug else { // Debug
Project::debugging = true; Project::debugging = true;
Terminal::get().print("\e[2mCompiling and debugging: " + label + "\e[m\n"); Terminal::get().print("\e[37mCompiling and debugging: " + label + "\e[m\n");
Terminal::get().async_process(compile, run_path, [project = project->shared_from_this(), run, run_path, debug_remote_host = command.debug_remote_host](int exit_status) { Terminal::get().async_process(compile, run_path, [project = project->shared_from_this(), run, run_path, debug_remote_host = command.debug_remote_host](int exit_status) {
if(exit_status != EXIT_SUCCESS) if(exit_status != EXIT_SUCCESS)
Project::debugging = false; Project::debugging = false;
@ -1997,14 +1997,14 @@ bool Window::on_key_press_event(GdkEventKey *event) {
} }
} }
else if(!command.debug) { else if(!command.debug) {
Terminal::get().async_print("\e[2mRunning: " + label + "\e[m\n"); Terminal::get().async_print("\e[37mRunning: " + label + "\e[m\n");
Terminal::get().async_process(run, run_path, [label](int exit_status) { Terminal::get().async_process(run, run_path, [label](int exit_status) {
Terminal::get().print("\e[2m" + label + " returned: " + (exit_status == 0 ? "\e[32m" : "\e[31m") + std::to_string(exit_status) + "\e[m\n"); Terminal::get().print("\e[37m" + label + " returned: " + (exit_status == 0 ? "\e[32m" : "\e[31m") + std::to_string(exit_status) + "\e[m\n");
}); });
} }
else { // Debug else { // Debug
Project::debugging = true; Project::debugging = true;
Terminal::get().async_print("\e[2mDebugging: " + label + "\e[m\n"); Terminal::get().async_print("\e[37mDebugging: " + label + "\e[m\n");
project->debug_start(run, run_path, command.debug_remote_host); project->debug_start(run, run_path, command.debug_remote_host);
} }
return true; return true;

78
tests/terminal_test.cpp

@ -252,8 +252,10 @@ int main() {
auto iter = buffer->begin(); auto iter = buffer->begin();
iter.forward_chars(15); iter.forward_chars(15);
assert(iter.starts_tag(terminal.red_tag)); assert(iter.starts_tag(terminal.red_tag));
assert(iter.starts_tag(terminal.bold_tag));
iter.forward_chars(7); iter.forward_chars(7);
assert(iter.ends_tag(terminal.red_tag)); assert(iter.ends_tag(terminal.red_tag));
assert(iter.ends_tag(terminal.bold_tag));
} }
{ {
terminal.clear(); terminal.clear();
@ -276,9 +278,15 @@ int main() {
iter.forward_visible_cursor_positions(3); iter.forward_visible_cursor_positions(3);
assert(iter.get_tags().empty()); assert(iter.get_tags().empty());
iter.forward_visible_cursor_positions(1); iter.forward_visible_cursor_positions(1);
assert(iter.get_tags() == std::vector<Glib::RefPtr<Gtk::TextTag>>{terminal.red_tag}); auto tags = iter.get_tags();
assert(tags.size() == 2);
assert(std::find(tags.begin(), tags.end(), Glib::RefPtr<Gtk::TextTag>{terminal.red_tag}) != tags.end());
assert(std::find(tags.begin(), tags.end(), Glib::RefPtr<Gtk::TextTag>{terminal.bold_tag}) != tags.end());
iter.forward_visible_cursor_positions(3); iter.forward_visible_cursor_positions(3);
assert(iter.get_tags() == std::vector<Glib::RefPtr<Gtk::TextTag>>{terminal.red_tag}); tags = iter.get_tags();
assert(tags.size() == 2);
assert(std::find(tags.begin(), tags.end(), Glib::RefPtr<Gtk::TextTag>{terminal.red_tag}) != tags.end());
assert(std::find(tags.begin(), tags.end(), Glib::RefPtr<Gtk::TextTag>{terminal.bold_tag}) != tags.end());
iter.forward_visible_cursor_positions(1); iter.forward_visible_cursor_positions(1);
assert(iter.get_tags().empty()); assert(iter.get_tags().empty());
} }
@ -295,6 +303,72 @@ int main() {
iter.forward_visible_cursor_positions(1); iter.forward_visible_cursor_positions(1);
assert(iter.get_tags().empty()); assert(iter.get_tags().empty());
} }
{
terminal.clear();
terminal.print("test\e[02mtest\e[0mtest");
assert(buffer->get_text(true) == "test\e[02mtest\e[0mtest");
assert(buffer->get_text(false) == "testtesttest");
auto iter = buffer->begin();
iter.forward_chars(9);
assert(iter.starts_tag(terminal.light_tag));
iter.forward_chars(4);
assert(iter.ends_tag(terminal.light_tag));
}
{
terminal.clear();
terminal.print("test\e[02mtest\e[22mtest");
assert(buffer->get_text(true) == "test\e[02mtest\e[22mtest");
assert(buffer->get_text(false) == "testtesttest");
auto iter = buffer->begin();
iter.forward_chars(9);
assert(iter.starts_tag(terminal.light_tag));
iter.forward_chars(4);
assert(iter.ends_tag(terminal.light_tag));
}
{
terminal.clear();
terminal.print("test\e[03mtest\e[23mtest");
assert(buffer->get_text(true) == "test\e[03mtest\e[23mtest");
assert(buffer->get_text(false) == "testtesttest");
auto iter = buffer->begin();
iter.forward_chars(9);
assert(iter.starts_tag(terminal.italic_tag));
iter.forward_chars(4);
assert(iter.ends_tag(terminal.italic_tag));
}
{
terminal.clear();
terminal.print("test\e[04mtest\e[24mtest");
assert(buffer->get_text(true) == "test\e[04mtest\e[24mtest");
assert(buffer->get_text(false) == "testtesttest");
auto iter = buffer->begin();
iter.forward_chars(9);
assert(iter.starts_tag(terminal.underline_tag));
iter.forward_chars(4);
assert(iter.ends_tag(terminal.underline_tag));
}
{
terminal.clear();
terminal.print("test\e[09mtest\e[29mtest");
assert(buffer->get_text(true) == "test\e[09mtest\e[29mtest");
assert(buffer->get_text(false) == "testtesttest");
auto iter = buffer->begin();
iter.forward_chars(9);
assert(iter.starts_tag(terminal.strikethrough_tag));
iter.forward_chars(4);
assert(iter.ends_tag(terminal.strikethrough_tag));
}
{
terminal.clear();
terminal.print("test\e[31mtest\e[32mtest\e[0m");
assert(buffer->get_text(true) == "test\e[31mtest\e[32mtest\e[0m");
assert(buffer->get_text(false) == "testtesttest");
auto iter = buffer->begin();
iter.forward_chars(9);
assert(iter.starts_tag(terminal.red_tag));
iter.forward_chars(4);
assert(iter.ends_tag(terminal.red_tag));
}
// async_process tests // async_process tests
{ {

Loading…
Cancel
Save