Improvement of Improve error reporting with buggy custom G-code sections #1516

Errors in the file output templates are reported in mono-spaced font,
so that the arrow character ^ is displayed at the right column
pointing to the offending spot.
This commit is contained in:
Vojtech Bubnik 2020-12-03 11:03:03 +01:00
parent 7afef2bbb5
commit 306acbdfb4
10 changed files with 40 additions and 32 deletions

View file

@ -20,7 +20,8 @@ SLIC3R_DERIVE_EXCEPTION(OutOfRange, LogicError);
SLIC3R_DERIVE_EXCEPTION(IOError, CriticalException); SLIC3R_DERIVE_EXCEPTION(IOError, CriticalException);
SLIC3R_DERIVE_EXCEPTION(FileIOError, IOError); SLIC3R_DERIVE_EXCEPTION(FileIOError, IOError);
SLIC3R_DERIVE_EXCEPTION(HostNetworkError, IOError); SLIC3R_DERIVE_EXCEPTION(HostNetworkError, IOError);
SLIC3R_DERIVE_EXCEPTION(ExportError, CriticalException); SLIC3R_DERIVE_EXCEPTION(ExportError, CriticalException);
SLIC3R_DERIVE_EXCEPTION(PlaceholderParserError, RuntimeError);
// Runtime exception produced by Slicer. Such exception cancels the slicing process and it shall be shown in notifications. // Runtime exception produced by Slicer. Such exception cancels the slicing process and it shall be shown in notifications.
SLIC3R_DERIVE_EXCEPTION(SlicingError, Exception); SLIC3R_DERIVE_EXCEPTION(SlicingError, Exception);
#undef SLIC3R_DERIVE_EXCEPTION #undef SLIC3R_DERIVE_EXCEPTION

View file

@ -756,7 +756,7 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessor::Result* re
msg += " !!!!! Failed to process the custom G-code template ...\n"; msg += " !!!!! Failed to process the custom G-code template ...\n";
msg += "and\n"; msg += "and\n";
msg += " !!!!! End of an error report for the custom G-code template ...\n"; msg += " !!!!! End of an error report for the custom G-code template ...\n";
throw Slic3r::RuntimeError(msg); throw Slic3r::PlaceholderParserError(msg);
} }
BOOST_LOG_TRIVIAL(debug) << "Start processing gcode, " << log_memory_info(); BOOST_LOG_TRIVIAL(debug) << "Start processing gcode, " << log_memory_info();

View file

@ -1304,7 +1304,7 @@ static std::string process_macro(const std::string &templ, client::MyContext &co
if (!context.error_message.empty()) { if (!context.error_message.empty()) {
if (context.error_message.back() != '\n' && context.error_message.back() != '\r') if (context.error_message.back() != '\n' && context.error_message.back() != '\r')
context.error_message += '\n'; context.error_message += '\n';
throw Slic3r::RuntimeError(context.error_message); throw Slic3r::PlaceholderParserError(context.error_message);
} }
return output; return output;
} }

View file

@ -40,11 +40,11 @@ public:
const DynamicConfig* external_config() const { return m_external_config; } const DynamicConfig* external_config() const { return m_external_config; }
// Fill in the template using a macro processing language. // Fill in the template using a macro processing language.
// Throws Slic3r::RuntimeError on syntax or runtime error. // Throws Slic3r::PlaceholderParserError on syntax or runtime error.
std::string process(const std::string &templ, unsigned int current_extruder_id = 0, const DynamicConfig *config_override = nullptr) const; std::string process(const std::string &templ, unsigned int current_extruder_id = 0, const DynamicConfig *config_override = nullptr) const;
// Evaluate a boolean expression using the full expressive power of the PlaceholderParser boolean expression syntax. // Evaluate a boolean expression using the full expressive power of the PlaceholderParser boolean expression syntax.
// Throws Slic3r::RuntimeError on syntax or runtime error. // Throws Slic3r::PlaceholderParserError on syntax or runtime error.
static bool evaluate_boolean_expression(const std::string &templ, const DynamicConfig &config, const DynamicConfig *config_override = nullptr); static bool evaluate_boolean_expression(const std::string &templ, const DynamicConfig &config, const DynamicConfig *config_override = nullptr);
// Update timestamp, year, month, day, hour, minute, second variables at the provided config. // Update timestamp, year, month, day, hour, minute, second variables at the provided config.

View file

@ -69,7 +69,7 @@ std::string PrintBase::output_filename(const std::string &format, const std::str
filename = boost::filesystem::change_extension(filename, default_ext); filename = boost::filesystem::change_extension(filename, default_ext);
return filename.string(); return filename.string();
} catch (std::runtime_error &err) { } catch (std::runtime_error &err) {
throw Slic3r::RuntimeError(L("Failed processing of the output_filename_format template.") + "\n" + err.what()); throw Slic3r::PlaceholderParserError(L("Failed processing of the output_filename_format template.") + "\n" + err.what());
} }
} }

View file

@ -221,16 +221,16 @@ void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt
} }
} }
void show_error(wxWindow* parent, const wxString& message) void show_error(wxWindow* parent, const wxString& message, bool monospaced_font)
{ {
ErrorDialog msg(parent, message); ErrorDialog msg(parent, message, monospaced_font);
msg.ShowModal(); msg.ShowModal();
} }
void show_error(wxWindow* parent, const char* message) void show_error(wxWindow* parent, const char* message, bool monospaced_font)
{ {
assert(message); assert(message);
show_error(parent, wxString::FromUTF8(message)); show_error(parent, wxString::FromUTF8(message), monospaced_font);
} }
void show_error_id(int id, const std::string& message) void show_error_id(int id, const std::string& message)

View file

@ -39,9 +39,11 @@ extern void add_menus(wxMenuBar *menu, int event_preferences_changed, int event_
// Change option value in config // Change option value in config
void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt_key, const boost::any& value, int opt_index = 0); void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt_key, const boost::any& value, int opt_index = 0);
void show_error(wxWindow* parent, const wxString& message); // If monospaced_font is true, the error message is displayed using html <code><pre></pre></code> tags,
void show_error(wxWindow* parent, const char* message); // so that the code formatting will be preserved. This is useful for reporting errors from the placeholder parser.
inline void show_error(wxWindow* parent, const std::string& message) { show_error(parent, message.c_str()); } void show_error(wxWindow* parent, const wxString& message, bool monospaced_font = false);
void show_error(wxWindow* parent, const char* message, bool monospaced_font = false);
inline void show_error(wxWindow* parent, const std::string& message, bool monospaced_font = false) { show_error(parent, message.c_str(), monospaced_font); }
void show_error_id(int id, const std::string& message); // For Perl void show_error_id(int id, const std::string& message); // For Perl
void show_info(wxWindow* parent, const wxString& message, const wxString& title = wxString()); void show_info(wxWindow* parent, const wxString& message, const wxString& title = wxString());
void show_info(wxWindow* parent, const char* message, const char* title = nullptr); void show_info(wxWindow* parent, const char* message, const char* title = nullptr);

View file

@ -64,12 +64,9 @@ MsgDialog::MsgDialog(wxWindow *parent, const wxString &title, const wxString &he
SetSizerAndFit(topsizer); SetSizerAndFit(topsizer);
} }
MsgDialog::~MsgDialog() {}
// ErrorDialog // ErrorDialog
ErrorDialog::ErrorDialog(wxWindow *parent, const wxString &msg) ErrorDialog::ErrorDialog(wxWindow *parent, const wxString &msg, bool monospaced_font)
: MsgDialog(parent, wxString::Format(_(L("%s error")), SLIC3R_APP_NAME), : MsgDialog(parent, wxString::Format(_(L("%s error")), SLIC3R_APP_NAME),
wxString::Format(_(L("%s has encountered an error")), SLIC3R_APP_NAME), wxString::Format(_(L("%s has encountered an error")), SLIC3R_APP_NAME),
wxID_NONE) wxID_NONE)
@ -80,17 +77,21 @@ ErrorDialog::ErrorDialog(wxWindow *parent, const wxString &msg)
{ {
html->SetMinSize(wxSize(40 * wxGetApp().em_unit(), -1)); html->SetMinSize(wxSize(40 * wxGetApp().em_unit(), -1));
wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
wxFont monospace = wxSystemSettings::GetFont(wxSYS_ANSI_FIXED_FONT);
wxColour text_clr = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT); wxColour text_clr = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
wxColour bgr_clr = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); wxColour bgr_clr = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
auto text_clr_str = wxString::Format(wxT("#%02X%02X%02X"), text_clr.Red(), text_clr.Green(), text_clr.Blue()); auto text_clr_str = wxString::Format(wxT("#%02X%02X%02X"), text_clr.Red(), text_clr.Green(), text_clr.Blue());
auto bgr_clr_str = wxString::Format(wxT("#%02X%02X%02X"), bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue()); auto bgr_clr_str = wxString::Format(wxT("#%02X%02X%02X"), bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue());
const int font_size = font.GetPointSize()-1; const int font_size = font.GetPointSize()-1;
int size[] = {font_size, font_size, font_size, font_size, font_size, font_size, font_size}; int size[] = {font_size, font_size, font_size, font_size, font_size, font_size, font_size};
html->SetFonts(font.GetFaceName(), font.GetFaceName(), size); html->SetFonts(font.GetFaceName(), monospace.GetFaceName(), size);
html->SetBorders(2); html->SetBorders(2);
std::string msg_escaped = xml_escape(msg.ToUTF8().data()); std::string msg_escaped = xml_escape(msg.ToUTF8().data());
boost::replace_all(msg_escaped, "\r\n", "<br>"); boost::replace_all(msg_escaped, "\r\n", "<br>");
boost::replace_all(msg_escaped, "\n", "<br>"); boost::replace_all(msg_escaped, "\n", "<br>");
if (monospaced_font)
// Code formatting will be preserved. This is useful for reporting errors from the placeholder parser.
msg_escaped = std::string("<pre><code>") + msg_escaped + "</code></pre>";
html->SetPage("<html><body bgcolor=\"" + bgr_clr_str + "\"><font color=\"" + text_clr_str + "\">" + wxString::FromUTF8(msg_escaped.data()) + "</font></body></html>"); html->SetPage("<html><body bgcolor=\"" + bgr_clr_str + "\"><font color=\"" + text_clr_str + "\">" + wxString::FromUTF8(msg_escaped.data()) + "</font></body></html>");
content_sizer->Add(html, 1, wxEXPAND); content_sizer->Add(html, 1, wxEXPAND);
} }
@ -105,9 +106,5 @@ ErrorDialog::ErrorDialog(wxWindow *parent, const wxString &msg)
Fit(); Fit();
} }
ErrorDialog::~ErrorDialog() {}
} }
} }

View file

@ -25,7 +25,7 @@ struct MsgDialog : wxDialog
MsgDialog(const MsgDialog &) = delete; MsgDialog(const MsgDialog &) = delete;
MsgDialog &operator=(MsgDialog &&) = delete; MsgDialog &operator=(MsgDialog &&) = delete;
MsgDialog &operator=(const MsgDialog &) = delete; MsgDialog &operator=(const MsgDialog &) = delete;
virtual ~MsgDialog(); virtual ~MsgDialog() = default;
// TODO: refactor with CreateStdDialogButtonSizer usage // TODO: refactor with CreateStdDialogButtonSizer usage
@ -52,12 +52,14 @@ protected:
class ErrorDialog : public MsgDialog class ErrorDialog : public MsgDialog
{ {
public: public:
ErrorDialog(wxWindow *parent, const wxString &msg); // If monospaced_font is true, the error message is displayed using html <code><pre></pre></code> tags,
// so that the code formatting will be preserved. This is useful for reporting errors from the placeholder parser.
ErrorDialog(wxWindow *parent, const wxString &msg, bool courier_font);
ErrorDialog(ErrorDialog &&) = delete; ErrorDialog(ErrorDialog &&) = delete;
ErrorDialog(const ErrorDialog &) = delete; ErrorDialog(const ErrorDialog &) = delete;
ErrorDialog &operator=(ErrorDialog &&) = delete; ErrorDialog &operator=(ErrorDialog &&) = delete;
ErrorDialog &operator=(const ErrorDialog &) = delete; ErrorDialog &operator=(const ErrorDialog &) = delete;
virtual ~ErrorDialog(); virtual ~ErrorDialog() = default;
private: private:
wxString msg; wxString msg;

View file

@ -3652,7 +3652,7 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt)
else else
show_error(q, message); show_error(q, message);
} else } else
notification_manager->push_slicing_error_notification(message, *q->get_current_canvas3D()); notification_manager->push_slicing_error_notification(message, *q->get_current_canvas3D());
this->statusbar()->set_status_text(from_u8(message)); this->statusbar()->set_status_text(from_u8(message));
if (evt.invalidate_plater()) if (evt.invalidate_plater())
{ {
@ -5216,9 +5216,12 @@ void Plater::export_gcode(bool prefer_removable)
if (state & priv::UPDATE_BACKGROUND_PROCESS_INVALID) if (state & priv::UPDATE_BACKGROUND_PROCESS_INVALID)
return; return;
default_output_file = this->p->background_process.output_filepath_for_project(into_path(get_project_filename(".3mf"))); default_output_file = this->p->background_process.output_filepath_for_project(into_path(get_project_filename(".3mf")));
} } catch (const Slic3r::PlaceholderParserError &ex) {
catch (const std::exception &ex) { // Show the error with monospaced font.
show_error(this, ex.what()); show_error(this, ex.what(), true);
return;
} catch (const std::exception &ex) {
show_error(this, ex.what(), false);
return; return;
} }
default_output_file = fs::path(Slic3r::fold_utf8_to_ascii(default_output_file.string())); default_output_file = fs::path(Slic3r::fold_utf8_to_ascii(default_output_file.string()));
@ -5576,9 +5579,12 @@ void Plater::send_gcode()
if (state & priv::UPDATE_BACKGROUND_PROCESS_INVALID) if (state & priv::UPDATE_BACKGROUND_PROCESS_INVALID)
return; return;
default_output_file = this->p->background_process.output_filepath_for_project(into_path(get_project_filename(".3mf"))); default_output_file = this->p->background_process.output_filepath_for_project(into_path(get_project_filename(".3mf")));
} } catch (const Slic3r::PlaceholderParserError& ex) {
catch (const std::exception &ex) { // Show the error with monospaced font.
show_error(this, ex.what()); show_error(this, ex.what(), true);
return;
} catch (const std::exception& ex) {
show_error(this, ex.what(), false);
return; return;
} }
default_output_file = fs::path(Slic3r::fold_utf8_to_ascii(default_output_file.string())); default_output_file = fs::path(Slic3r::fold_utf8_to_ascii(default_output_file.string()));