Fix built-in placeholders missing from custom G-code and output filenames (#13892)
* fix: restore version placeholder in custom G-code
PlaceholderParser sets "version" in its constructor, but Print::apply() calls clear_config() which wipes it. Unlike timestamp/user (restored during G-code export), version was never restored, so [version]/{version} threw "Variable does not exist" in custom G-code while working in output filenames.
Re-set version after both clear_config() calls so it resolves everywhere.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: resolve timestamp and user placeholders in File header G-code
file_start_gcode is processed via print.placeholder_parser() directly, before the G-code parser integration copy that restores timestamp/user. As a result {timestamp}, {year}..{second} and {user} threw "Variable does not exist" in the File header G-code field while working in Machine start/end G-code.
Inject fresh timestamp and user into the file_start_gcode config so they resolve, matching the other custom G-code fields.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: expose initial_extruder and extruded_*_total placeholders in output filenames
PrintStatistics exposed initial_tool (not its documented alias initial_extruder) and total_weight/extruded_volume (not the documented extruded_weight_total/extruded_volume_total). Filename formats using the missing names failed with "not a variable name".
Add the missing aliases to PrintStatistics::config() and placeholders().
Fixes #12436
Fixes #10708
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2549,6 +2549,9 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
std::string top_gcode_template = print.config().file_start_gcode.value;
|
||||
if (!top_gcode_template.empty()) {
|
||||
DynamicConfig top_config;
|
||||
// file_start_gcode runs before the parser copy that normally restores these, so set them here.
|
||||
PlaceholderParser::update_timestamp(top_config);
|
||||
PlaceholderParser::update_user_name(top_config);
|
||||
top_config.set_key_value("print_time_sec", new ConfigOptionString(GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Print_Time_Sec_Placeholder)));
|
||||
top_config.set_key_value("used_filament_length", new ConfigOptionString(GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Used_Filament_Length_Placeholder)));
|
||||
std::string top_gcode = print.placeholder_parser().process(top_gcode_template, 0, &top_config);
|
||||
|
||||
@@ -3609,9 +3609,12 @@ DynamicConfig PrintStatistics::config() const
|
||||
config.set_key_value("total_cost", new ConfigOptionFloat(this->total_cost));
|
||||
config.set_key_value("total_toolchanges", new ConfigOptionInt(this->total_toolchanges));
|
||||
config.set_key_value("total_weight", new ConfigOptionFloat(this->total_weight));
|
||||
config.set_key_value("extruded_weight_total", new ConfigOptionFloat(this->total_weight));
|
||||
config.set_key_value("extruded_volume_total", new ConfigOptionFloat(this->total_extruded_volume));
|
||||
config.set_key_value("total_wipe_tower_cost", new ConfigOptionFloat(this->total_wipe_tower_cost));
|
||||
config.set_key_value("total_wipe_tower_filament", new ConfigOptionFloat(this->total_wipe_tower_filament));
|
||||
config.set_key_value("initial_tool", new ConfigOptionInt(static_cast<int>(this->initial_tool)));
|
||||
config.set_key_value("initial_extruder", new ConfigOptionInt(static_cast<int>(this->initial_tool)));
|
||||
return config;
|
||||
}
|
||||
|
||||
@@ -3620,8 +3623,8 @@ DynamicConfig PrintStatistics::placeholders()
|
||||
DynamicConfig config;
|
||||
for (const std::string key : {
|
||||
"print_time", "normal_print_time", "silent_print_time",
|
||||
"used_filament", "extruded_volume", "total_cost", "total_weight",
|
||||
"initial_tool", "total_toolchanges", "total_wipe_tower_cost", "total_wipe_tower_filament"})
|
||||
"used_filament", "extruded_volume", "extruded_volume_total", "total_cost", "total_weight", "extruded_weight_total",
|
||||
"initial_tool", "initial_extruder", "total_toolchanges", "total_wipe_tower_cost", "total_wipe_tower_filament"})
|
||||
config.set_key_value(key, new ConfigOptionString(std::string("{") + key + "}"));
|
||||
return config;
|
||||
}
|
||||
|
||||
@@ -1254,6 +1254,8 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" %1%: found full_config_diff changed.")%__LINE__;
|
||||
update_apply_status(this->invalidate_step(psGCodeExport));
|
||||
m_placeholder_parser.clear_config();
|
||||
// clear_config() wiped the constructor-set "version"; restore it for custom G-code.
|
||||
m_placeholder_parser.set("version", std::string(SoftFever_VERSION));
|
||||
// Set the profile aliases for the PrintBase::output_filename()
|
||||
m_placeholder_parser.set("print_preset", new_full_config.option("print_settings_id")->clone());
|
||||
m_placeholder_parser.set("filament_preset", new_full_config.option("filament_settings_id")->clone());
|
||||
@@ -1630,6 +1632,8 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" %1%: full_config_diff previous empty, need to apply now.")%__LINE__;
|
||||
|
||||
m_placeholder_parser.clear_config();
|
||||
// clear_config() wiped the constructor-set "version"; restore it for custom G-code.
|
||||
m_placeholder_parser.set("version", std::string(SoftFever_VERSION));
|
||||
// Set the profile aliases for the PrintBase::output_filename()
|
||||
m_placeholder_parser.set("print_preset", new_full_config.option("print_settings_id")->clone());
|
||||
m_placeholder_parser.set("filament_preset", new_full_config.option("filament_settings_id")->clone());
|
||||
|
||||
Reference in New Issue
Block a user