@@ -181,41 +181,111 @@ define(function (require, exports, module) {
181181 const sourceText = editor . getTextBetween ( sourceRange . from , sourceRange . to ) ;
182182 const targetIndent = editor . getTextBetween ( { line : targetRange . from . line , ch : 0 } , targetRange . from ) ;
183183
184- // creating a batch operation so that undo in live preview works fine
185- editor . document . batchOperation ( function ( ) {
186- // first, we need to remove the source code from its initial position
187- editor . replaceRange ( "" , sourceRange . from , sourceRange . to ) ;
184+ // Check if source is before target to determine order of operations
185+ // check if the source is before target or after the target
186+ // we need this because
187+ // If source is before target → we need to insert first, then remove
188+ // If target is before source → remove first, then insert
189+ const sourceBeforeTarget =
190+ sourceRange . from . line < targetRange . from . line ||
191+ ( sourceRange . from . line === targetRange . from . line && sourceRange . from . ch < targetRange . from . ch ) ;
192+
193+ // this function is to clean up the empty lines after an element is removed
194+ function cleanupAfterRemoval ( range ) {
195+ const lineToCheck = range . from . line ;
196+
197+ // check if the line where element was removed is now empty
198+ if ( lineToCheck < editor . lineCount ( ) ) {
199+ const currentLineText = editor . getLine ( lineToCheck ) ;
200+ if ( currentLineText && currentLineText . trim ( ) === "" ) {
201+ // remove the empty line
202+ const lineStart = { line : lineToCheck , ch : 0 } ;
203+ const lineEnd = { line : lineToCheck + 1 , ch : 0 } ;
204+ editor . replaceRange ( "" , lineStart , lineEnd ) ;
205+ }
206+ }
188207
189- // since we remove content from the source, we want to clear the extra line
190- if ( sourceRange . from . line !== 0 ) {
191- const prevLineText = editor . getLine ( sourceRange . from . line - 1 ) ;
192- const chPrevLine = prevLineText ? prevLineText . length : 0 ;
193- editor . replaceRange ( "" , { line : sourceRange . from . line - 1 , ch : chPrevLine } , sourceRange . from ) ;
208+ // also we need to check the previous line if it became empty
209+ if ( lineToCheck > 0 ) {
210+ const prevLineText = editor . getLine ( lineToCheck - 1 ) ;
211+ if ( prevLineText && prevLineText . trim ( ) === "" ) {
212+ const lineStart = { line : lineToCheck - 1 , ch : 0 } ;
213+ const lineEnd = { line : lineToCheck , ch : 0 } ;
214+ editor . replaceRange ( "" , lineStart , lineEnd ) ;
215+ }
194216 }
217+ }
218+
219+ // this function is to make sure that we insert elements with proper indentation
220+ function insertElementWithIndentation ( insertPos , insertAfterMode , useTargetIndent ) {
221+ const indent = useTargetIndent ? targetIndent : targetIndent ;
222+
223+ if ( insertAfterMode ) {
224+ // Insert after the target element
225+ editor . replaceRange ( "\n" + indent + sourceText , insertPos ) ;
226+ } else {
227+ // Insert before the target element
228+ const insertLine = insertPos . line ;
229+ const lineStart = { line : insertLine , ch : 0 } ;
230+
231+ // Get current line content to preserve any existing indentation structure
232+ const currentLine = editor . getLine ( insertLine ) ;
195233
196- // recalculate the target range, as the source text is not removed
197- const updatedTargetRange = HTMLInstrumentation . getPositionFromTagId ( editor , targetId ) ;
198- if ( ! updatedTargetRange ) {
199- return ;
234+ if ( currentLine && currentLine . trim ( ) === "" ) {
235+ // the line is empty, replace it entirely
236+ editor . replaceRange ( indent + sourceText , lineStart , { line : insertLine , ch : currentLine . length } ) ;
237+ } else {
238+ // the line has content, insert before it
239+ editor . replaceRange ( indent + sourceText + "\n" , lineStart ) ;
240+ }
200241 }
242+ }
201243
202- if ( insertAfter ) {
203- const insertPos = {
204- line : updatedTargetRange . to . line ,
205- ch : updatedTargetRange . to . ch
206- } ;
244+ // creating a batch operation so that undo in live preview works fine
245+ editor . document . batchOperation ( function ( ) {
246+ if ( sourceBeforeTarget ) {
247+ // this handles the case when source is before target: insert first, then remove
248+ if ( insertAfter ) {
249+ const insertPos = {
250+ line : targetRange . to . line ,
251+ ch : targetRange . to . ch
252+ } ;
253+ insertElementWithIndentation ( insertPos , true , true ) ;
254+ } else {
255+ // insert before target
256+ insertElementWithIndentation ( targetRange . from , false , true ) ;
257+ }
207258
208- editor . replaceRange ( "\n" + targetIndent + sourceText , insertPos ) ;
259+ // Now remove the source element (NOTE: the positions have shifted)
260+ const updatedSourceRange = HTMLInstrumentation . getPositionFromTagId ( editor , sourceId ) ;
261+ if ( updatedSourceRange ) {
262+ editor . replaceRange ( "" , updatedSourceRange . from , updatedSourceRange . to ) ;
263+ cleanupAfterRemoval ( updatedSourceRange ) ;
264+ }
209265 } else {
210- // insert before
211- const targetText = editor . getTextBetween ( updatedTargetRange . from , updatedTargetRange . to ) ;
266+ // This handles the case when target is before source: remove first, then insert
267+ // Store source range before removal
268+ const originalSourceRange = { ...sourceRange } ;
269+
270+ // Remove the source element first
271+ editor . replaceRange ( "" , sourceRange . from , sourceRange . to ) ;
272+ cleanupAfterRemoval ( originalSourceRange ) ;
273+
274+ // Recalculate target range after source removal as the positions have shifted
275+ const updatedTargetRange = HTMLInstrumentation . getPositionFromTagId ( editor , targetId ) ;
276+ if ( ! updatedTargetRange ) {
277+ return ;
278+ }
212279
213- // to check if there is only indentation and no text before it
214- if ( targetIndent . trim ( ) === "" ) {
215- const finalText = sourceText + '\n' + targetIndent + targetText ;
216- editor . replaceRange ( finalText , updatedTargetRange . from , updatedTargetRange . to ) ;
280+ if ( insertAfter ) {
281+ const insertPos = {
282+ line : updatedTargetRange . to . line ,
283+ ch : updatedTargetRange . to . ch
284+ } ;
285+ insertElementWithIndentation ( insertPos , true , true ) ;
217286 } else {
218- editor . replaceRange ( sourceText + targetText , updatedTargetRange . from , updatedTargetRange . to ) ;
287+ // Insert before target
288+ insertElementWithIndentation ( updatedTargetRange . from , false , true ) ;
219289 }
220290 }
221291 } ) ;
0 commit comments