From a4b60756004bb1c2d9437b5d704a18adc570e0e9 Mon Sep 17 00:00:00 2001
From: Alessandro Ranellucci <aar@cpan.org>
Date: Tue, 29 Apr 2014 17:06:31 +0200
Subject: [PATCH] Fixed regression and ambiguity about multiple-value
 placeholders like [first_layer_temperature_1]. Includes several unit tests
 covering regression. #1899

---
 lib/Slic3r/GCode/PlaceholderParser.pm |  8 +++--
 lib/Slic3r/GUI/SkeinPanel.pm          | 11 +++++--
 t/custom_gcode.t                      | 43 +++++++++++++++++++++++++--
 3 files changed, 55 insertions(+), 7 deletions(-)

diff --git a/lib/Slic3r/GCode/PlaceholderParser.pm b/lib/Slic3r/GCode/PlaceholderParser.pm
index 4b6011e48..e3dc30e8c 100644
--- a/lib/Slic3r/GCode/PlaceholderParser.pm
+++ b/lib/Slic3r/GCode/PlaceholderParser.pm
@@ -43,7 +43,8 @@ sub apply_config {
     foreach my $opt_key (@opt_keys) {
         my $value = $config->$opt_key;
         next unless ref($value) eq 'ARRAY';
-        $m->{"${opt_key}_${_}"} = $value->[$_] for 0..$#$value;
+        $m->{"${opt_key}_" . ($_+1)} = $value->[$_] for 0..$#$value;
+        $m->{$opt_key} = $value->[0];
         if ($Slic3r::Config::Options->{$opt_key}{type} eq 'point') {
             $m->{"${opt_key}_X"} = $value->[0];
             $m->{"${opt_key}_Y"} = $value->[1];
@@ -70,7 +71,10 @@ sub process {
     }
     {
         my $regex = join '|', keys %{$self->_multiple};
-        $string =~ s/\[($regex)\]/$self->_multiple->{$1}/eg;
+        $string =~ s/\[($regex)\]/$self->_multiple->{$1}/egx;
+        
+        # unhandled indices are populated using the first value, except _0 which is ignored for safety
+        $string =~ s/\[($regex)_[1-9]\d*\]/$self->_multiple->{$1}/egx;
     }
     
     return $string;
diff --git a/lib/Slic3r/GUI/SkeinPanel.pm b/lib/Slic3r/GUI/SkeinPanel.pm
index b130b4784..1b7f9487d 100644
--- a/lib/Slic3r/GUI/SkeinPanel.pm
+++ b/lib/Slic3r/GUI/SkeinPanel.pm
@@ -484,16 +484,21 @@ sub config {
     } else {
         # TODO: handle dirty presets.
         # perhaps plater shouldn't expose dirty presets at all in multi-extruder environments.
+        my $i = -1;
         foreach my $preset_idx ($self->{plater}->filament_presets) {
+            $i++;
             my $preset = $self->{options_tabs}{filament}->get_preset($preset_idx);
             my $config = $self->{options_tabs}{filament}->get_preset_config($preset);
             if (!$filament_config) {
-                $filament_config = $config;
+                $filament_config = $config->clone;
                 next;
             }
             foreach my $opt_key (@{$config->get_keys}) {
-                next unless ref $filament_config->get($opt_key) eq 'ARRAY';
-                push @{ $filament_config->get($opt_key) }, $config->get($opt_key)->[0];
+                my $value = $filament_config->get($opt_key);
+                next unless ref $value eq 'ARRAY';
+                $value->[$i] = $config->get($opt_key)->[0];
+                use XXX; YYY $value if $opt_key eq 'first_layer_temperature';
+                $filament_config->set($opt_key, $value);
             }
         }
     }
diff --git a/t/custom_gcode.t b/t/custom_gcode.t
index 6e678d690..e734886c0 100644
--- a/t/custom_gcode.t
+++ b/t/custom_gcode.t
@@ -1,4 +1,4 @@
-use Test::More tests => 6;
+use Test::More tests => 14;
 use strict;
 use warnings;
 
@@ -46,7 +46,7 @@ use Slic3r::Test;
 {
     my $parser = Slic3r::GCode::PlaceholderParser->new;
     $parser->apply_config(my $config = Slic3r::Config->new_from_defaults);
-    is $parser->process('[temperature_[foo]]', { foo => '0' }),
+    is $parser->process('[temperature_[foo]]', { foo => '1' }),
         $config->temperature->[0],
         "nested config options";
 }
@@ -67,4 +67,43 @@ use Slic3r::Test;
     ok $gcode =~ /HEIGHT:$h/, 'region config options are replaced in custom G-code';
 }
 
+{
+    my $config = Slic3r::Config->new;
+    $config->set('extruder', 2);
+    $config->set('first_layer_temperature', [200,205]);
+    
+    {
+        my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
+        my $gcode = Slic3r::Test::gcode($print);
+        ok $gcode =~ /M104 S205 T1/, 'temperature set correctly for non-zero yet single extruder';
+        ok $gcode !~ /M104 S\d+ T0/, 'unused extruder correctly ignored';
+    }
+    
+    $config->set('infill_extruder', 1);
+    {
+        my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
+        my $gcode = Slic3r::Test::gcode($print);
+        ok $gcode =~ /M104 S200 T0/, 'temperature set correctly for first extruder';
+        ok $gcode =~ /M104 S205 T1/, 'temperature set correctly for second extruder';
+    }
+    
+    $config->set('start_gcode', qq!
+;__temp0:[infill_extruder][first_layer_temperature_0]__
+;__temp1:[first_layer_temperature_1]__
+;__temp2:[first_layer_temperature_2]__
+;__temp3:[first_layer_temperature_3]__
+    !);
+    {
+        my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
+        my $gcode = Slic3r::Test::gcode($print);
+        # we use the [infill_extruder] placeholder to make sure this test doesn't
+        # catch a false positive caused by the unparsed start G-code option itself
+        # being embedded in the G-code
+        ok $gcode =~ /temp0:1\[/, 'temperature placeholder for _0 ignored';
+        ok $gcode =~ /temp1:200/, 'temperature placeholder for first extruder correctly populated';
+        ok $gcode =~ /temp2:205/, 'temperature placeholder for second extruder correctly populated';
+        ok $gcode =~ /temp3:200/, 'tempearture placeholder for unused extruder populated with first value';
+    }
+}
+
 __END__