ide-assi 0.341.0 → 0.343.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -234948,72 +234948,91 @@ class IdeDiff extends HTMLElement {
234948
234948
  const diffs = dmp.diff_main(asisSrc, tobeSrc);
234949
234949
  dmp.diff_cleanupSemantic(diffs);
234950
234950
 
234951
- const asisBuilder = new RangeSetBuilder();
234952
- const tobeBuilder = new RangeSetBuilder();
234951
+ // 모든 데코레이션을 builder에 추가하기 전에 수집합니다.
234952
+ const asisDecorationsToAdd = [];
234953
+ const tobeDecorationsToAdd = [];
234953
234954
 
234954
- let asisCursor = 0;
234955
- let tobeCursor = 0;
234955
+ let asisCursor = 0; // asis 에디터에서의 현재 텍스트 오프셋
234956
+ let tobeCursor = 0; // tobe 에디터에서의 현재 텍스트 오프셋
234956
234957
 
234957
234958
  for (const [op, text] of diffs) {
234958
234959
  const len = text.length;
234959
234960
 
234960
234961
  switch (op) {
234961
- case diffMatchPatchExports.diff_match_patch.DIFF_INSERT:
234962
- tobeBuilder.add(
234963
- tobeCursor, tobeCursor + len,
234964
- Decoration.mark({ class: "cm-inserted-inline" })
234965
- );
234962
+ case diffMatchPatchExports.diff_match_patch.DIFF_INSERT: // 추가된 텍스트
234963
+ // tobe 쪽에 인라인 데코레이션 추가
234964
+ tobeDecorationsToAdd.push({
234965
+ from: tobeCursor,
234966
+ to: tobeCursor + len,
234967
+ deco: Decoration.mark({ class: "cm-inserted-inline" })
234968
+ });
234966
234969
 
234967
- // Inserted lines background
234968
- const tobeLines = text.split('\n');
234970
+ // tobe 쪽에 줄 배경 데코레이션 추가 (삽입된 줄)
234971
+ // text가 여러 줄일 수 있으므로 각 줄에 적용
234969
234972
  let currentTobeLineOffset = tobeCursor;
234970
- for(let i = 0; i < tobeLines.length; i++) {
234971
- // Get line start/end from the *current* editor view's document
234972
- const lineStart = this.#tobeEditorView.state.doc.lineAt(currentTobeLineOffset).from;
234973
- // For the last segment of a multi-line insertion, the end is just current offset + segment length
234974
- // Otherwise, it's the end of the current line in the doc.
234975
- const lineEnd = i === tobeLines.length - 1 ? currentTobeLineOffset + tobeLines[i].length : this.#tobeEditorView.state.doc.lineAt(currentTobeLineOffset).to;
234976
-
234977
- tobeBuilder.add(
234978
- lineStart, lineEnd,
234979
- Decoration.line({ class: "cm-inserted-line-bg" })
234980
- );
234981
- currentTobeLineOffset += tobeLines[i].length + 1; // Move to next line start
234973
+ const tobeLines = text.split('\n');
234974
+ for (let i = 0; i < tobeLines.length; i++) {
234975
+ // 현재 에디터 뷰의 문서에서 줄 정보를 가져옵니다.
234976
+ // 이전에 `tobeEditorView`가 전역 변수처럼 사용되었을 가능성을 위해 `this.#tobeEditorView`로 명시
234977
+ const line = this.#tobeEditorView.state.doc.lineAt(currentTobeLineOffset);
234978
+ tobeDecorationsToAdd.push({
234979
+ from: line.from,
234980
+ to: line.to,
234981
+ deco: Decoration.line({ class: "cm-inserted-line-bg" })
234982
+ });
234983
+ currentTobeLineOffset += tobeLines[i].length + 1; // 다음 줄 시작 위치로 이동
234982
234984
  }
234983
234985
 
234984
234986
  tobeCursor += len;
234985
234987
  break;
234986
234988
 
234987
- case diffMatchPatchExports.diff_match_patch.DIFF_DELETE:
234988
- asisBuilder.add(
234989
- asisCursor, asisCursor + len,
234990
- Decoration.mark({ class: "cm-deleted-inline" })
234991
- );
234989
+ case diffMatchPatchExports.diff_match_patch.DIFF_DELETE: // 삭제된 텍스트
234990
+ // asis 쪽에 인라인 데코레이션 추가
234991
+ asisDecorationsToAdd.push({
234992
+ from: asisCursor,
234993
+ to: asisCursor + len,
234994
+ deco: Decoration.mark({ class: "cm-deleted-inline" })
234995
+ });
234992
234996
 
234993
- // Deleted lines background
234994
- const asisLines = text.split('\n');
234997
+ // asis 쪽에 줄 배경 데코레이션 추가 (삭제된 줄)
234995
234998
  let currentAsisLineOffset = asisCursor;
234996
- for(let i = 0; i < asisLines.length; i++) {
234997
- const lineStart = this.#asisEditorView.state.doc.lineAt(currentAsisLineOffset).from;
234998
- const lineEnd = i === asisLines.length - 1 ? currentAsisLineOffset + asisLines[i].length : this.#asisEditorView.state.doc.lineAt(currentAsisLineOffset).to;
234999
-
235000
- asisBuilder.add(
235001
- lineStart, lineEnd,
235002
- Decoration.line({ class: "cm-deleted-line-bg" })
235003
- );
234999
+ const asisLines = text.split('\n');
235000
+ for (let i = 0; i < asisLines.length; i++) {
235001
+ const line = this.#asisEditorView.state.doc.lineAt(currentAsisLineOffset);
235002
+ asisDecorationsToAdd.push({
235003
+ from: line.from,
235004
+ to: line.to,
235005
+ deco: Decoration.line({ class: "cm-deleted-line-bg" })
235006
+ });
235004
235007
  currentAsisLineOffset += asisLines[i].length + 1;
235005
235008
  }
235006
235009
 
235007
235010
  asisCursor += len;
235008
235011
  break;
235009
235012
 
235010
- case diffMatchPatchExports.diff_match_patch.DIFF_EQUAL:
235013
+ case diffMatchPatchExports.diff_match_patch.DIFF_EQUAL: // 변경되지 않은 텍스트
235011
235014
  asisCursor += len;
235012
235015
  tobeCursor += len;
235013
235016
  break;
235014
235017
  }
235015
235018
  }
235016
235019
 
235020
+ // ⭐️ 중요: 데코레이션들을 'from' 위치를 기준으로 정렬합니다.
235021
+ asisDecorationsToAdd.sort((a, b) => a.from - b.from);
235022
+ tobeDecorationsToAdd.sort((a, b) => a.from - b.from);
235023
+
235024
+ // 정렬된 데코레이션들을 RangeSetBuilder에 추가합니다.
235025
+ const asisBuilder = new RangeSetBuilder();
235026
+ for (const { from, to, deco } of asisDecorationsToAdd) {
235027
+ asisBuilder.add(from, to, deco);
235028
+ }
235029
+
235030
+ const tobeBuilder = new RangeSetBuilder();
235031
+ for (const { from, to, deco } of tobeDecorationsToAdd) {
235032
+ tobeBuilder.add(from, to, deco);
235033
+ }
235034
+
235035
+ // 데코레이션 업데이트를 위한 Effect를 디스패치합니다.
235017
235036
  this.#asisEditorView.dispatch({
235018
235037
  effects: setAsisDecorationsEffect.of(asisBuilder.finish())
235019
235038
  });
@@ -234944,72 +234944,91 @@ class IdeDiff extends HTMLElement {
234944
234944
  const diffs = dmp.diff_main(asisSrc, tobeSrc);
234945
234945
  dmp.diff_cleanupSemantic(diffs);
234946
234946
 
234947
- const asisBuilder = new RangeSetBuilder();
234948
- const tobeBuilder = new RangeSetBuilder();
234947
+ // 모든 데코레이션을 builder에 추가하기 전에 수집합니다.
234948
+ const asisDecorationsToAdd = [];
234949
+ const tobeDecorationsToAdd = [];
234949
234950
 
234950
- let asisCursor = 0;
234951
- let tobeCursor = 0;
234951
+ let asisCursor = 0; // asis 에디터에서의 현재 텍스트 오프셋
234952
+ let tobeCursor = 0; // tobe 에디터에서의 현재 텍스트 오프셋
234952
234953
 
234953
234954
  for (const [op, text] of diffs) {
234954
234955
  const len = text.length;
234955
234956
 
234956
234957
  switch (op) {
234957
- case diffMatchPatchExports.diff_match_patch.DIFF_INSERT:
234958
- tobeBuilder.add(
234959
- tobeCursor, tobeCursor + len,
234960
- Decoration.mark({ class: "cm-inserted-inline" })
234961
- );
234958
+ case diffMatchPatchExports.diff_match_patch.DIFF_INSERT: // 추가된 텍스트
234959
+ // tobe 쪽에 인라인 데코레이션 추가
234960
+ tobeDecorationsToAdd.push({
234961
+ from: tobeCursor,
234962
+ to: tobeCursor + len,
234963
+ deco: Decoration.mark({ class: "cm-inserted-inline" })
234964
+ });
234962
234965
 
234963
- // Inserted lines background
234964
- const tobeLines = text.split('\n');
234966
+ // tobe 쪽에 줄 배경 데코레이션 추가 (삽입된 줄)
234967
+ // text가 여러 줄일 수 있으므로 각 줄에 적용
234965
234968
  let currentTobeLineOffset = tobeCursor;
234966
- for(let i = 0; i < tobeLines.length; i++) {
234967
- // Get line start/end from the *current* editor view's document
234968
- const lineStart = this.#tobeEditorView.state.doc.lineAt(currentTobeLineOffset).from;
234969
- // For the last segment of a multi-line insertion, the end is just current offset + segment length
234970
- // Otherwise, it's the end of the current line in the doc.
234971
- const lineEnd = i === tobeLines.length - 1 ? currentTobeLineOffset + tobeLines[i].length : this.#tobeEditorView.state.doc.lineAt(currentTobeLineOffset).to;
234972
-
234973
- tobeBuilder.add(
234974
- lineStart, lineEnd,
234975
- Decoration.line({ class: "cm-inserted-line-bg" })
234976
- );
234977
- currentTobeLineOffset += tobeLines[i].length + 1; // Move to next line start
234969
+ const tobeLines = text.split('\n');
234970
+ for (let i = 0; i < tobeLines.length; i++) {
234971
+ // 현재 에디터 뷰의 문서에서 줄 정보를 가져옵니다.
234972
+ // 이전에 `tobeEditorView`가 전역 변수처럼 사용되었을 가능성을 위해 `this.#tobeEditorView`로 명시
234973
+ const line = this.#tobeEditorView.state.doc.lineAt(currentTobeLineOffset);
234974
+ tobeDecorationsToAdd.push({
234975
+ from: line.from,
234976
+ to: line.to,
234977
+ deco: Decoration.line({ class: "cm-inserted-line-bg" })
234978
+ });
234979
+ currentTobeLineOffset += tobeLines[i].length + 1; // 다음 줄 시작 위치로 이동
234978
234980
  }
234979
234981
 
234980
234982
  tobeCursor += len;
234981
234983
  break;
234982
234984
 
234983
- case diffMatchPatchExports.diff_match_patch.DIFF_DELETE:
234984
- asisBuilder.add(
234985
- asisCursor, asisCursor + len,
234986
- Decoration.mark({ class: "cm-deleted-inline" })
234987
- );
234985
+ case diffMatchPatchExports.diff_match_patch.DIFF_DELETE: // 삭제된 텍스트
234986
+ // asis 쪽에 인라인 데코레이션 추가
234987
+ asisDecorationsToAdd.push({
234988
+ from: asisCursor,
234989
+ to: asisCursor + len,
234990
+ deco: Decoration.mark({ class: "cm-deleted-inline" })
234991
+ });
234988
234992
 
234989
- // Deleted lines background
234990
- const asisLines = text.split('\n');
234993
+ // asis 쪽에 줄 배경 데코레이션 추가 (삭제된 줄)
234991
234994
  let currentAsisLineOffset = asisCursor;
234992
- for(let i = 0; i < asisLines.length; i++) {
234993
- const lineStart = this.#asisEditorView.state.doc.lineAt(currentAsisLineOffset).from;
234994
- const lineEnd = i === asisLines.length - 1 ? currentAsisLineOffset + asisLines[i].length : this.#asisEditorView.state.doc.lineAt(currentAsisLineOffset).to;
234995
-
234996
- asisBuilder.add(
234997
- lineStart, lineEnd,
234998
- Decoration.line({ class: "cm-deleted-line-bg" })
234999
- );
234995
+ const asisLines = text.split('\n');
234996
+ for (let i = 0; i < asisLines.length; i++) {
234997
+ const line = this.#asisEditorView.state.doc.lineAt(currentAsisLineOffset);
234998
+ asisDecorationsToAdd.push({
234999
+ from: line.from,
235000
+ to: line.to,
235001
+ deco: Decoration.line({ class: "cm-deleted-line-bg" })
235002
+ });
235000
235003
  currentAsisLineOffset += asisLines[i].length + 1;
235001
235004
  }
235002
235005
 
235003
235006
  asisCursor += len;
235004
235007
  break;
235005
235008
 
235006
- case diffMatchPatchExports.diff_match_patch.DIFF_EQUAL:
235009
+ case diffMatchPatchExports.diff_match_patch.DIFF_EQUAL: // 변경되지 않은 텍스트
235007
235010
  asisCursor += len;
235008
235011
  tobeCursor += len;
235009
235012
  break;
235010
235013
  }
235011
235014
  }
235012
235015
 
235016
+ // ⭐️ 중요: 데코레이션들을 'from' 위치를 기준으로 정렬합니다.
235017
+ asisDecorationsToAdd.sort((a, b) => a.from - b.from);
235018
+ tobeDecorationsToAdd.sort((a, b) => a.from - b.from);
235019
+
235020
+ // 정렬된 데코레이션들을 RangeSetBuilder에 추가합니다.
235021
+ const asisBuilder = new RangeSetBuilder();
235022
+ for (const { from, to, deco } of asisDecorationsToAdd) {
235023
+ asisBuilder.add(from, to, deco);
235024
+ }
235025
+
235026
+ const tobeBuilder = new RangeSetBuilder();
235027
+ for (const { from, to, deco } of tobeDecorationsToAdd) {
235028
+ tobeBuilder.add(from, to, deco);
235029
+ }
235030
+
235031
+ // 데코레이션 업데이트를 위한 Effect를 디스패치합니다.
235013
235032
  this.#asisEditorView.dispatch({
235014
235033
  effects: setAsisDecorationsEffect.of(asisBuilder.finish())
235015
235034
  });
@@ -221,72 +221,91 @@ export class IdeDiff extends HTMLElement {
221
221
  const diffs = dmp.diff_main(asisSrc, tobeSrc);
222
222
  dmp.diff_cleanupSemantic(diffs);
223
223
 
224
- const asisBuilder = new RangeSetBuilder();
225
- const tobeBuilder = new RangeSetBuilder();
224
+ // 모든 데코레이션을 builder에 추가하기 전에 수집합니다.
225
+ const asisDecorationsToAdd = [];
226
+ const tobeDecorationsToAdd = [];
226
227
 
227
- let asisCursor = 0;
228
- let tobeCursor = 0;
228
+ let asisCursor = 0; // asis 에디터에서의 현재 텍스트 오프셋
229
+ let tobeCursor = 0; // tobe 에디터에서의 현재 텍스트 오프셋
229
230
 
230
231
  for (const [op, text] of diffs) {
231
232
  const len = text.length;
232
233
 
233
234
  switch (op) {
234
- case diff_match_patch.DIFF_INSERT:
235
- tobeBuilder.add(
236
- tobeCursor, tobeCursor + len,
237
- Decoration.mark({ class: "cm-inserted-inline" })
238
- );
239
-
240
- // Inserted lines background
241
- const tobeLines = text.split('\n');
235
+ case diff_match_patch.DIFF_INSERT: // 추가된 텍스트
236
+ // tobe 쪽에 인라인 데코레이션 추가
237
+ tobeDecorationsToAdd.push({
238
+ from: tobeCursor,
239
+ to: tobeCursor + len,
240
+ deco: Decoration.mark({ class: "cm-inserted-inline" })
241
+ });
242
+
243
+ // tobe 쪽에 줄 배경 데코레이션 추가 (삽입된 줄)
244
+ // text가 여러 줄일 수 있으므로 각 줄에 적용
242
245
  let currentTobeLineOffset = tobeCursor;
243
- for(let i = 0; i < tobeLines.length; i++) {
244
- // Get line start/end from the *current* editor view's document
245
- const lineStart = this.#tobeEditorView.state.doc.lineAt(currentTobeLineOffset).from;
246
- // For the last segment of a multi-line insertion, the end is just current offset + segment length
247
- // Otherwise, it's the end of the current line in the doc.
248
- const lineEnd = i === tobeLines.length - 1 ? currentTobeLineOffset + tobeLines[i].length : this.#tobeEditorView.state.doc.lineAt(currentTobeLineOffset).to;
249
-
250
- tobeBuilder.add(
251
- lineStart, lineEnd,
252
- Decoration.line({ class: "cm-inserted-line-bg" })
253
- );
254
- currentTobeLineOffset += tobeLines[i].length + 1; // Move to next line start
246
+ const tobeLines = text.split('\n');
247
+ for (let i = 0; i < tobeLines.length; i++) {
248
+ // 현재 에디터 뷰의 문서에서 줄 정보를 가져옵니다.
249
+ // 이전에 `tobeEditorView`가 전역 변수처럼 사용되었을 가능성을 위해 `this.#tobeEditorView`로 명시
250
+ const line = this.#tobeEditorView.state.doc.lineAt(currentTobeLineOffset);
251
+ tobeDecorationsToAdd.push({
252
+ from: line.from,
253
+ to: line.to,
254
+ deco: Decoration.line({ class: "cm-inserted-line-bg" })
255
+ });
256
+ currentTobeLineOffset += tobeLines[i].length + 1; // 다음 줄 시작 위치로 이동
255
257
  }
256
258
 
257
259
  tobeCursor += len;
258
260
  break;
259
261
 
260
- case diff_match_patch.DIFF_DELETE:
261
- asisBuilder.add(
262
- asisCursor, asisCursor + len,
263
- Decoration.mark({ class: "cm-deleted-inline" })
264
- );
262
+ case diff_match_patch.DIFF_DELETE: // 삭제된 텍스트
263
+ // asis 쪽에 인라인 데코레이션 추가
264
+ asisDecorationsToAdd.push({
265
+ from: asisCursor,
266
+ to: asisCursor + len,
267
+ deco: Decoration.mark({ class: "cm-deleted-inline" })
268
+ });
265
269
 
266
- // Deleted lines background
267
- const asisLines = text.split('\n');
270
+ // asis 쪽에 줄 배경 데코레이션 추가 (삭제된 줄)
268
271
  let currentAsisLineOffset = asisCursor;
269
- for(let i = 0; i < asisLines.length; i++) {
270
- const lineStart = this.#asisEditorView.state.doc.lineAt(currentAsisLineOffset).from;
271
- const lineEnd = i === asisLines.length - 1 ? currentAsisLineOffset + asisLines[i].length : this.#asisEditorView.state.doc.lineAt(currentAsisLineOffset).to;
272
-
273
- asisBuilder.add(
274
- lineStart, lineEnd,
275
- Decoration.line({ class: "cm-deleted-line-bg" })
276
- );
272
+ const asisLines = text.split('\n');
273
+ for (let i = 0; i < asisLines.length; i++) {
274
+ const line = this.#asisEditorView.state.doc.lineAt(currentAsisLineOffset);
275
+ asisDecorationsToAdd.push({
276
+ from: line.from,
277
+ to: line.to,
278
+ deco: Decoration.line({ class: "cm-deleted-line-bg" })
279
+ });
277
280
  currentAsisLineOffset += asisLines[i].length + 1;
278
281
  }
279
282
 
280
283
  asisCursor += len;
281
284
  break;
282
285
 
283
- case diff_match_patch.DIFF_EQUAL:
286
+ case diff_match_patch.DIFF_EQUAL: // 변경되지 않은 텍스트
284
287
  asisCursor += len;
285
288
  tobeCursor += len;
286
289
  break;
287
290
  }
288
291
  }
289
292
 
293
+ // ⭐️ 중요: 데코레이션들을 'from' 위치를 기준으로 정렬합니다.
294
+ asisDecorationsToAdd.sort((a, b) => a.from - b.from);
295
+ tobeDecorationsToAdd.sort((a, b) => a.from - b.from);
296
+
297
+ // 정렬된 데코레이션들을 RangeSetBuilder에 추가합니다.
298
+ const asisBuilder = new RangeSetBuilder();
299
+ for (const { from, to, deco } of asisDecorationsToAdd) {
300
+ asisBuilder.add(from, to, deco);
301
+ }
302
+
303
+ const tobeBuilder = new RangeSetBuilder();
304
+ for (const { from, to, deco } of tobeDecorationsToAdd) {
305
+ tobeBuilder.add(from, to, deco);
306
+ }
307
+
308
+ // 데코레이션 업데이트를 위한 Effect를 디스패치합니다.
290
309
  this.#asisEditorView.dispatch({
291
310
  effects: setAsisDecorationsEffect.of(asisBuilder.finish())
292
311
  });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ide-assi",
3
3
  "type": "module",
4
- "version": "0.341.0",
4
+ "version": "0.343.0",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "exports": {
@@ -221,72 +221,91 @@ export class IdeDiff extends HTMLElement {
221
221
  const diffs = dmp.diff_main(asisSrc, tobeSrc);
222
222
  dmp.diff_cleanupSemantic(diffs);
223
223
 
224
- const asisBuilder = new RangeSetBuilder();
225
- const tobeBuilder = new RangeSetBuilder();
224
+ // 모든 데코레이션을 builder에 추가하기 전에 수집합니다.
225
+ const asisDecorationsToAdd = [];
226
+ const tobeDecorationsToAdd = [];
226
227
 
227
- let asisCursor = 0;
228
- let tobeCursor = 0;
228
+ let asisCursor = 0; // asis 에디터에서의 현재 텍스트 오프셋
229
+ let tobeCursor = 0; // tobe 에디터에서의 현재 텍스트 오프셋
229
230
 
230
231
  for (const [op, text] of diffs) {
231
232
  const len = text.length;
232
233
 
233
234
  switch (op) {
234
- case diff_match_patch.DIFF_INSERT:
235
- tobeBuilder.add(
236
- tobeCursor, tobeCursor + len,
237
- Decoration.mark({ class: "cm-inserted-inline" })
238
- );
239
-
240
- // Inserted lines background
241
- const tobeLines = text.split('\n');
235
+ case diff_match_patch.DIFF_INSERT: // 추가된 텍스트
236
+ // tobe 쪽에 인라인 데코레이션 추가
237
+ tobeDecorationsToAdd.push({
238
+ from: tobeCursor,
239
+ to: tobeCursor + len,
240
+ deco: Decoration.mark({ class: "cm-inserted-inline" })
241
+ });
242
+
243
+ // tobe 쪽에 줄 배경 데코레이션 추가 (삽입된 줄)
244
+ // text가 여러 줄일 수 있으므로 각 줄에 적용
242
245
  let currentTobeLineOffset = tobeCursor;
243
- for(let i = 0; i < tobeLines.length; i++) {
244
- // Get line start/end from the *current* editor view's document
245
- const lineStart = this.#tobeEditorView.state.doc.lineAt(currentTobeLineOffset).from;
246
- // For the last segment of a multi-line insertion, the end is just current offset + segment length
247
- // Otherwise, it's the end of the current line in the doc.
248
- const lineEnd = i === tobeLines.length - 1 ? currentTobeLineOffset + tobeLines[i].length : this.#tobeEditorView.state.doc.lineAt(currentTobeLineOffset).to;
249
-
250
- tobeBuilder.add(
251
- lineStart, lineEnd,
252
- Decoration.line({ class: "cm-inserted-line-bg" })
253
- );
254
- currentTobeLineOffset += tobeLines[i].length + 1; // Move to next line start
246
+ const tobeLines = text.split('\n');
247
+ for (let i = 0; i < tobeLines.length; i++) {
248
+ // 현재 에디터 뷰의 문서에서 줄 정보를 가져옵니다.
249
+ // 이전에 `tobeEditorView`가 전역 변수처럼 사용되었을 가능성을 위해 `this.#tobeEditorView`로 명시
250
+ const line = this.#tobeEditorView.state.doc.lineAt(currentTobeLineOffset);
251
+ tobeDecorationsToAdd.push({
252
+ from: line.from,
253
+ to: line.to,
254
+ deco: Decoration.line({ class: "cm-inserted-line-bg" })
255
+ });
256
+ currentTobeLineOffset += tobeLines[i].length + 1; // 다음 줄 시작 위치로 이동
255
257
  }
256
258
 
257
259
  tobeCursor += len;
258
260
  break;
259
261
 
260
- case diff_match_patch.DIFF_DELETE:
261
- asisBuilder.add(
262
- asisCursor, asisCursor + len,
263
- Decoration.mark({ class: "cm-deleted-inline" })
264
- );
262
+ case diff_match_patch.DIFF_DELETE: // 삭제된 텍스트
263
+ // asis 쪽에 인라인 데코레이션 추가
264
+ asisDecorationsToAdd.push({
265
+ from: asisCursor,
266
+ to: asisCursor + len,
267
+ deco: Decoration.mark({ class: "cm-deleted-inline" })
268
+ });
265
269
 
266
- // Deleted lines background
267
- const asisLines = text.split('\n');
270
+ // asis 쪽에 줄 배경 데코레이션 추가 (삭제된 줄)
268
271
  let currentAsisLineOffset = asisCursor;
269
- for(let i = 0; i < asisLines.length; i++) {
270
- const lineStart = this.#asisEditorView.state.doc.lineAt(currentAsisLineOffset).from;
271
- const lineEnd = i === asisLines.length - 1 ? currentAsisLineOffset + asisLines[i].length : this.#asisEditorView.state.doc.lineAt(currentAsisLineOffset).to;
272
-
273
- asisBuilder.add(
274
- lineStart, lineEnd,
275
- Decoration.line({ class: "cm-deleted-line-bg" })
276
- );
272
+ const asisLines = text.split('\n');
273
+ for (let i = 0; i < asisLines.length; i++) {
274
+ const line = this.#asisEditorView.state.doc.lineAt(currentAsisLineOffset);
275
+ asisDecorationsToAdd.push({
276
+ from: line.from,
277
+ to: line.to,
278
+ deco: Decoration.line({ class: "cm-deleted-line-bg" })
279
+ });
277
280
  currentAsisLineOffset += asisLines[i].length + 1;
278
281
  }
279
282
 
280
283
  asisCursor += len;
281
284
  break;
282
285
 
283
- case diff_match_patch.DIFF_EQUAL:
286
+ case diff_match_patch.DIFF_EQUAL: // 변경되지 않은 텍스트
284
287
  asisCursor += len;
285
288
  tobeCursor += len;
286
289
  break;
287
290
  }
288
291
  }
289
292
 
293
+ // ⭐️ 중요: 데코레이션들을 'from' 위치를 기준으로 정렬합니다.
294
+ asisDecorationsToAdd.sort((a, b) => a.from - b.from);
295
+ tobeDecorationsToAdd.sort((a, b) => a.from - b.from);
296
+
297
+ // 정렬된 데코레이션들을 RangeSetBuilder에 추가합니다.
298
+ const asisBuilder = new RangeSetBuilder();
299
+ for (const { from, to, deco } of asisDecorationsToAdd) {
300
+ asisBuilder.add(from, to, deco);
301
+ }
302
+
303
+ const tobeBuilder = new RangeSetBuilder();
304
+ for (const { from, to, deco } of tobeDecorationsToAdd) {
305
+ tobeBuilder.add(from, to, deco);
306
+ }
307
+
308
+ // 데코레이션 업데이트를 위한 Effect를 디스패치합니다.
290
309
  this.#asisEditorView.dispatch({
291
310
  effects: setAsisDecorationsEffect.of(asisBuilder.finish())
292
311
  });