@@ -130,7 +130,7 @@ private function updateData(array $newData)
130130 $ this ->arrayTypeForDepths [$ this ->depth ] = $ this ->isHash ($ currentData ) ? self ::ARRAY_TYPE_HASH : self ::ARRAY_TYPE_SEQUENCE ;
131131
132132 $ this ->log (sprintf (
133- 'Array type: %s, format: %s ' ,
133+ 'Changing array type & format via updateData() ' ,
134134 $ this ->arrayTypeForDepths [$ this ->depth ],
135135 $ this ->arrayFormatForDepths [$ this ->depth ]
136136 ));
@@ -333,12 +333,7 @@ private function addNewKeyToYaml($key, $value)
333333 // because we're inside a multi-line array, put this item
334334 // onto the *next* line & indent it
335335
336- // But, if the *value* is an array, then ITS children will
337- // also need to be indented artificially by the same amount
338- $ newYamlValue = str_replace ("\n" , "\n" .$ this ->getCurrentIndentation (), $ newYamlValue );
339-
340- // now add the new line & indentation to the top-level
341- $ newYamlValue = "\n" .$ this ->getCurrentIndentation ().$ newYamlValue ;
336+ $ newYamlValue = "\n" .$ this ->indentMultilineYamlArray ($ newYamlValue );
342337 } else {
343338 if ($ firstItemInArray ) {
344339 // avoid the starting "," if first item in array
@@ -454,13 +449,23 @@ private function changeValueInYaml($value)
454449
455450 $ endValuePosition = $ this ->findEndPositionOfValue ($ originalVal );
456451
457- // empty space between key & value
458- $ newDataString = ' ' .$ this ->convertToYaml ($ value );
452+ $ newYamlValue = $ this ->convertToYaml ($ value );
453+ if (!is_array ($ originalVal ) && is_array ($ value )) {
454+ // we're converting from a scalar to a (multiline) array
455+ // this means we need to break onto the next line
456+
457+ // increase the indentation
458+ $ this ->manuallyIncrementIndentation ();
459+ $ newYamlValue = "\n" .$ this ->indentMultilineYamlArray ($ newYamlValue );
460+ } else {
461+ // empty space between key & value
462+ $ newYamlValue = ' ' .$ newYamlValue ;
463+ }
459464 $ newContents = substr ($ this ->contents , 0 , $ this ->currentPosition )
460- .$ newDataString
465+ .$ newYamlValue
461466 .substr ($ this ->contents , $ endValuePosition );
462467
463- $ newPosition = $ this ->currentPosition + \strlen ($ newDataString );
468+ $ newPosition = $ this ->currentPosition + \strlen ($ newYamlValue );
464469
465470 $ newData = $ this ->currentData ;
466471 $ newData = $ this ->setValueAtCurrentPath ($ value , $ newData );
@@ -783,6 +788,19 @@ private function advanceCurrentPosition(int $newPosition)
783788 return ;
784789 }
785790
791+ /*
792+ * A bit of a workaround. At times, this function will be called when the
793+ * position is at the beginning of the line: so, one character *after*
794+ * a line break. In that case, if there are a group of spaces at the
795+ * beginning of this first line, they *should* be used to calculate the new
796+ * indentation. To force this, if we detect this situation, we move one
797+ * character backwards, so that the first line is considered a valid line
798+ * to look for indentation.
799+ */
800+ if ($ this ->isCharLineBreak (substr ($ this ->contents , $ originalPosition - 1 , 1 ))) {
801+ $ originalPosition --;
802+ }
803+
786804 // look for empty lines and track the current indentation
787805 $ advancedContent = substr ($ this ->contents , $ originalPosition , $ newPosition - $ originalPosition );
788806 $ previousIndentation = $ this ->indentationForDepths [$ this ->depth ];
@@ -801,14 +819,7 @@ private function advanceCurrentPosition(int $newPosition)
801819 }
802820 }
803821
804- /*
805- if ($newIndentation === $previousIndentation) {
806- $this->log(sprintf('Indentation unchanged: %d', $newIndentation));
807- } else {
808- $this->log(sprintf('Indentation changed to: %d', $newIndentation));
809- }
810- */
811-
822+ $ this ->log (sprintf ('Calculating new indentation: changing from %d to %d ' , $ this ->indentationForDepths [$ this ->depth ], $ newIndentation ), true );
812823 $ this ->indentationForDepths [$ this ->depth ] = $ newIndentation ;
813824 }
814825
@@ -837,12 +848,15 @@ private function log(string $message, $includeContent = false)
837848 'key ' => isset ($ this ->currentPath [$ this ->depth ]) ? $ this ->currentPath [$ this ->depth ] : 'n/a ' ,
838849 'depth ' => $ this ->depth ,
839850 'position ' => $ this ->currentPosition ,
851+ 'indentation ' => $ this ->indentationForDepths [$ this ->depth ],
852+ 'type ' => $ this ->arrayTypeForDepths [$ this ->depth ],
853+ 'format ' => $ this ->arrayFormatForDepths [$ this ->depth ],
840854 ];
841855
842856 if ($ includeContent ) {
843857 $ context ['content ' ] = sprintf (
844- '%s... ' ,
845- str_replace (["\r\n" , "\n" ], ['\r\n ' , '\n ' ], substr ($ this ->contents , $ this ->currentPosition , 20 ))
858+ '>%s< ' ,
859+ str_replace (["\r\n" , "\n" ], ['\r\n ' , '\n ' ], substr ($ this ->contents , $ this ->currentPosition , 50 ))
846860 );
847861 }
848862
@@ -872,7 +886,11 @@ private function guessNextArrayTypeAndAdvance(): string
872886
873887 // get the next char & advance immediately
874888 $ nextCharacter = substr ($ this ->contents , $ this ->currentPosition , 1 );
875- $ this ->advanceCurrentPosition ($ this ->currentPosition + 1 );
889+ // advance, but without advanceCurrentPosition()
890+ // because we are either moving along one line until [ {
891+ // or we are finding a line break and stopping: indentation
892+ // should not be calculated
893+ $ this ->currentPosition ++;
876894
877895 if ($ this ->isCharLineBreak ($ nextCharacter )) {
878896 return self ::ARRAY_FORMAT_MULTILINE ;
@@ -1112,4 +1130,21 @@ private function isCharLineBreak(string $char): bool
11121130 {
11131131 return "\n" === $ char || "\r" === $ char ;
11141132 }
1133+
1134+ /**
1135+ * Takes an unindented multi-line YAML string and indents it so
1136+ * it can be inserted into the current position.
1137+ *
1138+ * Usually an empty line needs to be prepended to this result before
1139+ * adding to the content.
1140+ */
1141+ private function indentMultilineYamlArray (string $ yaml ): string
1142+ {
1143+ // But, if the *value* is an array, then ITS children will
1144+ // also need to be indented artificially by the same amount
1145+ $ yaml = str_replace ("\n" , "\n" .$ this ->getCurrentIndentation (), $ yaml );
1146+
1147+ // now indent this level
1148+ return $ this ->getCurrentIndentation ().$ yaml ;
1149+ }
11151150}
0 commit comments