ide-assi 0.344.0 → 0.346.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,7 +234948,6 @@ class IdeDiff extends HTMLElement {
234948
234948
  const diffs = dmp.diff_main(asisSrc, tobeSrc);
234949
234949
  dmp.diff_cleanupSemantic(diffs);
234950
234950
 
234951
- // Separate collections for line decorations and mark decorations
234952
234951
  const asisLineDecos = [];
234953
234952
  const asisMarkDecos = [];
234954
234953
  const tobeLineDecos = [];
@@ -234962,48 +234961,59 @@ class IdeDiff extends HTMLElement {
234962
234961
 
234963
234962
  switch (op) {
234964
234963
  case diffMatchPatchExports.diff_match_patch.DIFF_INSERT: // Added text
234965
- // Inline mark decoration for tobe
234966
234964
  tobeMarkDecos.push({
234967
234965
  from: tobeCursor,
234968
234966
  to: tobeCursor + len,
234969
234967
  deco: Decoration.mark({ class: "cm-inserted-inline" })
234970
234968
  });
234971
234969
 
234972
- // Line background decoration for tobe (for each line in the inserted text)
234973
234970
  let currentTobeLineOffset = tobeCursor;
234974
234971
  const tobeLines = text.split('\n');
234975
234972
  for (let i = 0; i < tobeLines.length; i++) {
234976
- const line = this.#tobeEditorView.state.doc.lineAt(currentTobeLineOffset);
234977
- tobeLineDecos.push({
234978
- from: line.from,
234979
- to: line.to,
234980
- deco: Decoration.line({ class: "cm-inserted-line-bg" })
234981
- });
234982
- currentTobeLineOffset += tobeLines[i].length + 1; // Move to the start of the next line segment
234973
+ // ⭐️ 중요: lineAt() 호출 전에 유효한 문서 범위 내에 있는지 확인
234974
+ if (currentTobeLineOffset < this.#tobeEditorView.state.doc.length) {
234975
+ const line = this.#tobeEditorView.state.doc.lineAt(currentTobeLineOffset);
234976
+ tobeLineDecos.push({
234977
+ from: line.from,
234978
+ to: line.to,
234979
+ deco: Decoration.line({ class: "cm-inserted-line-bg" })
234980
+ });
234981
+ }
234982
+ // 다음 줄의 시작 위치 계산. 마지막 줄이 아니면 +1 (개행문자)
234983
+ currentTobeLineOffset += tobeLines[i].length + (i < tobeLines.length -1 ? 1 : 0);
234984
+ // 만약 마지막 줄이 비어있다면, 더 이상 진행하지 않도록 방지
234985
+ if (i === tobeLines.length - 1 && tobeLines[i].length === 0 && text.endsWith('\n') === false) {
234986
+ // 마지막 줄이 빈 줄이고 텍스트가 개행으로 끝나지 않으면 (오프셋이 더 이상 증가할 필요 없음)
234987
+ break;
234988
+ }
234983
234989
  }
234984
234990
 
234985
234991
  tobeCursor += len;
234986
234992
  break;
234987
234993
 
234988
234994
  case diffMatchPatchExports.diff_match_patch.DIFF_DELETE: // Deleted text
234989
- // Inline mark decoration for asis
234990
234995
  asisMarkDecos.push({
234991
234996
  from: asisCursor,
234992
234997
  to: asisCursor + len,
234993
234998
  deco: Decoration.mark({ class: "cm-deleted-inline" })
234994
234999
  });
234995
235000
 
234996
- // Line background decoration for asis (for each line in the deleted text)
234997
235001
  let currentAsisLineOffset = asisCursor;
234998
235002
  const asisLines = text.split('\n');
234999
235003
  for (let i = 0; i < asisLines.length; i++) {
235000
- const line = this.#asisEditorView.state.doc.lineAt(currentAsisLineOffset);
235001
- asisLineDecos.push({
235002
- from: line.from,
235003
- to: line.to,
235004
- deco: Decoration.line({ class: "cm-deleted-line-bg" })
235005
- });
235006
- currentAsisLineOffset += asisLines[i].length + 1;
235004
+ // ⭐️ 중요: lineAt() 호출 전에 유효한 문서 범위 내에 있는지 확인
235005
+ if (currentAsisLineOffset < this.#asisEditorView.state.doc.length) {
235006
+ const line = this.#asisEditorView.state.doc.lineAt(currentAsisLineOffset);
235007
+ asisLineDecos.push({
235008
+ from: line.from,
235009
+ to: line.to,
235010
+ deco: Decoration.line({ class: "cm-deleted-line-bg" })
235011
+ });
235012
+ }
235013
+ currentAsisLineOffset += asisLines[i].length + (i < asisLines.length -1 ? 1 : 0);
235014
+ if (i === asisLines.length - 1 && asisLines[i].length === 0 && text.endsWith('\n') === false) {
235015
+ break;
235016
+ }
235007
235017
  }
235008
235018
 
235009
235019
  asisCursor += len;
@@ -235016,14 +235026,13 @@ class IdeDiff extends HTMLElement {
235016
235026
  }
235017
235027
  }
235018
235028
 
235019
- // Sort all collections by 'from' position
235020
- // Although separating builders helps, sorting is still a good practice.
235029
+ // Sort all collections by 'from' position (항상 좋은 습관)
235021
235030
  asisLineDecos.sort((a, b) => a.from - b.from);
235022
235031
  asisMarkDecos.sort((a, b) => a.from - b.from);
235023
235032
  tobeLineDecos.sort((a, b) => a.from - b.from);
235024
235033
  tobeMarkDecos.sort((a, b) => a.from - b.from);
235025
235034
 
235026
- // Build separate RangeSets for lines and marks for ASIS editor
235035
+ // ASIS 에디터용 마크 데코레이션을 위한 별도 RangeSetBuilder 생성
235027
235036
  const asisLineBuilder = new RangeSetBuilder();
235028
235037
  for (const { from, to, deco } of asisLineDecos) {
235029
235038
  asisLineBuilder.add(from, to, deco);
@@ -235033,14 +235042,12 @@ class IdeDiff extends HTMLElement {
235033
235042
  asisMarkBuilder.add(from, to, deco);
235034
235043
  }
235035
235044
 
235036
- // Combine line and mark RangeSets for ASIS editor
235037
- // The `RangeSet.join()` static method is used to combine multiple RangeSets.
235045
+ // ASIS 에디터용 마크 RangeSet 결합
235038
235046
  const finalAsisDecorations = asisLineBuilder.finish().update({
235039
- add: asisMarkBuilder.finish().children // Combine children of mark builder's RangeSet
235047
+ add: asisMarkBuilder.finish().children
235040
235048
  });
235041
235049
 
235042
-
235043
- // Build separate RangeSets for lines and marks for TOBE editor
235050
+ // TOBE 에디터용 줄 및 마크 데코레이션을 위한 별도 RangeSetBuilder 생성
235044
235051
  const tobeLineBuilder = new RangeSetBuilder();
235045
235052
  for (const { from, to, deco } of tobeLineDecos) {
235046
235053
  tobeLineBuilder.add(from, to, deco);
@@ -235050,13 +235057,12 @@ class IdeDiff extends HTMLElement {
235050
235057
  tobeMarkBuilder.add(from, to, deco);
235051
235058
  }
235052
235059
 
235053
- // Combine line and mark RangeSets for TOBE editor
235060
+ // TOBE 에디터용 마크 RangeSet 결합
235054
235061
  const finalTobeDecorations = tobeLineBuilder.finish().update({
235055
235062
  add: tobeMarkBuilder.finish().children
235056
235063
  });
235057
235064
 
235058
-
235059
- // Dispatch effects to update decorations
235065
+ // 데코레이션 업데이트를 위한 Effect 디스패치
235060
235066
  this.#asisEditorView.dispatch({
235061
235067
  effects: setAsisDecorationsEffect.of(finalAsisDecorations)
235062
235068
  });
@@ -234944,7 +234944,6 @@ class IdeDiff extends HTMLElement {
234944
234944
  const diffs = dmp.diff_main(asisSrc, tobeSrc);
234945
234945
  dmp.diff_cleanupSemantic(diffs);
234946
234946
 
234947
- // Separate collections for line decorations and mark decorations
234948
234947
  const asisLineDecos = [];
234949
234948
  const asisMarkDecos = [];
234950
234949
  const tobeLineDecos = [];
@@ -234958,48 +234957,59 @@ class IdeDiff extends HTMLElement {
234958
234957
 
234959
234958
  switch (op) {
234960
234959
  case diffMatchPatchExports.diff_match_patch.DIFF_INSERT: // Added text
234961
- // Inline mark decoration for tobe
234962
234960
  tobeMarkDecos.push({
234963
234961
  from: tobeCursor,
234964
234962
  to: tobeCursor + len,
234965
234963
  deco: Decoration.mark({ class: "cm-inserted-inline" })
234966
234964
  });
234967
234965
 
234968
- // Line background decoration for tobe (for each line in the inserted text)
234969
234966
  let currentTobeLineOffset = tobeCursor;
234970
234967
  const tobeLines = text.split('\n');
234971
234968
  for (let i = 0; i < tobeLines.length; i++) {
234972
- const line = this.#tobeEditorView.state.doc.lineAt(currentTobeLineOffset);
234973
- tobeLineDecos.push({
234974
- from: line.from,
234975
- to: line.to,
234976
- deco: Decoration.line({ class: "cm-inserted-line-bg" })
234977
- });
234978
- currentTobeLineOffset += tobeLines[i].length + 1; // Move to the start of the next line segment
234969
+ // ⭐️ 중요: lineAt() 호출 전에 유효한 문서 범위 내에 있는지 확인
234970
+ if (currentTobeLineOffset < this.#tobeEditorView.state.doc.length) {
234971
+ const line = this.#tobeEditorView.state.doc.lineAt(currentTobeLineOffset);
234972
+ tobeLineDecos.push({
234973
+ from: line.from,
234974
+ to: line.to,
234975
+ deco: Decoration.line({ class: "cm-inserted-line-bg" })
234976
+ });
234977
+ }
234978
+ // 다음 줄의 시작 위치 계산. 마지막 줄이 아니면 +1 (개행문자)
234979
+ currentTobeLineOffset += tobeLines[i].length + (i < tobeLines.length -1 ? 1 : 0);
234980
+ // 만약 마지막 줄이 비어있다면, 더 이상 진행하지 않도록 방지
234981
+ if (i === tobeLines.length - 1 && tobeLines[i].length === 0 && text.endsWith('\n') === false) {
234982
+ // 마지막 줄이 빈 줄이고 텍스트가 개행으로 끝나지 않으면 (오프셋이 더 이상 증가할 필요 없음)
234983
+ break;
234984
+ }
234979
234985
  }
234980
234986
 
234981
234987
  tobeCursor += len;
234982
234988
  break;
234983
234989
 
234984
234990
  case diffMatchPatchExports.diff_match_patch.DIFF_DELETE: // Deleted text
234985
- // Inline mark decoration for asis
234986
234991
  asisMarkDecos.push({
234987
234992
  from: asisCursor,
234988
234993
  to: asisCursor + len,
234989
234994
  deco: Decoration.mark({ class: "cm-deleted-inline" })
234990
234995
  });
234991
234996
 
234992
- // Line background decoration for asis (for each line in the deleted text)
234993
234997
  let currentAsisLineOffset = asisCursor;
234994
234998
  const asisLines = text.split('\n');
234995
234999
  for (let i = 0; i < asisLines.length; i++) {
234996
- const line = this.#asisEditorView.state.doc.lineAt(currentAsisLineOffset);
234997
- asisLineDecos.push({
234998
- from: line.from,
234999
- to: line.to,
235000
- deco: Decoration.line({ class: "cm-deleted-line-bg" })
235001
- });
235002
- currentAsisLineOffset += asisLines[i].length + 1;
235000
+ // ⭐️ 중요: lineAt() 호출 전에 유효한 문서 범위 내에 있는지 확인
235001
+ if (currentAsisLineOffset < this.#asisEditorView.state.doc.length) {
235002
+ const line = this.#asisEditorView.state.doc.lineAt(currentAsisLineOffset);
235003
+ asisLineDecos.push({
235004
+ from: line.from,
235005
+ to: line.to,
235006
+ deco: Decoration.line({ class: "cm-deleted-line-bg" })
235007
+ });
235008
+ }
235009
+ currentAsisLineOffset += asisLines[i].length + (i < asisLines.length -1 ? 1 : 0);
235010
+ if (i === asisLines.length - 1 && asisLines[i].length === 0 && text.endsWith('\n') === false) {
235011
+ break;
235012
+ }
235003
235013
  }
235004
235014
 
235005
235015
  asisCursor += len;
@@ -235012,14 +235022,13 @@ class IdeDiff extends HTMLElement {
235012
235022
  }
235013
235023
  }
235014
235024
 
235015
- // Sort all collections by 'from' position
235016
- // Although separating builders helps, sorting is still a good practice.
235025
+ // Sort all collections by 'from' position (항상 좋은 습관)
235017
235026
  asisLineDecos.sort((a, b) => a.from - b.from);
235018
235027
  asisMarkDecos.sort((a, b) => a.from - b.from);
235019
235028
  tobeLineDecos.sort((a, b) => a.from - b.from);
235020
235029
  tobeMarkDecos.sort((a, b) => a.from - b.from);
235021
235030
 
235022
- // Build separate RangeSets for lines and marks for ASIS editor
235031
+ // ASIS 에디터용 마크 데코레이션을 위한 별도 RangeSetBuilder 생성
235023
235032
  const asisLineBuilder = new RangeSetBuilder();
235024
235033
  for (const { from, to, deco } of asisLineDecos) {
235025
235034
  asisLineBuilder.add(from, to, deco);
@@ -235029,14 +235038,12 @@ class IdeDiff extends HTMLElement {
235029
235038
  asisMarkBuilder.add(from, to, deco);
235030
235039
  }
235031
235040
 
235032
- // Combine line and mark RangeSets for ASIS editor
235033
- // The `RangeSet.join()` static method is used to combine multiple RangeSets.
235041
+ // ASIS 에디터용 마크 RangeSet 결합
235034
235042
  const finalAsisDecorations = asisLineBuilder.finish().update({
235035
- add: asisMarkBuilder.finish().children // Combine children of mark builder's RangeSet
235043
+ add: asisMarkBuilder.finish().children
235036
235044
  });
235037
235045
 
235038
-
235039
- // Build separate RangeSets for lines and marks for TOBE editor
235046
+ // TOBE 에디터용 줄 및 마크 데코레이션을 위한 별도 RangeSetBuilder 생성
235040
235047
  const tobeLineBuilder = new RangeSetBuilder();
235041
235048
  for (const { from, to, deco } of tobeLineDecos) {
235042
235049
  tobeLineBuilder.add(from, to, deco);
@@ -235046,13 +235053,12 @@ class IdeDiff extends HTMLElement {
235046
235053
  tobeMarkBuilder.add(from, to, deco);
235047
235054
  }
235048
235055
 
235049
- // Combine line and mark RangeSets for TOBE editor
235056
+ // TOBE 에디터용 마크 RangeSet 결합
235050
235057
  const finalTobeDecorations = tobeLineBuilder.finish().update({
235051
235058
  add: tobeMarkBuilder.finish().children
235052
235059
  });
235053
235060
 
235054
-
235055
- // Dispatch effects to update decorations
235061
+ // 데코레이션 업데이트를 위한 Effect 디스패치
235056
235062
  this.#asisEditorView.dispatch({
235057
235063
  effects: setAsisDecorationsEffect.of(finalAsisDecorations)
235058
235064
  });
@@ -221,7 +221,6 @@ export class IdeDiff extends HTMLElement {
221
221
  const diffs = dmp.diff_main(asisSrc, tobeSrc);
222
222
  dmp.diff_cleanupSemantic(diffs);
223
223
 
224
- // Separate collections for line decorations and mark decorations
225
224
  const asisLineDecos = [];
226
225
  const asisMarkDecos = [];
227
226
  const tobeLineDecos = [];
@@ -235,48 +234,59 @@ export class IdeDiff extends HTMLElement {
235
234
 
236
235
  switch (op) {
237
236
  case diff_match_patch.DIFF_INSERT: // Added text
238
- // Inline mark decoration for tobe
239
237
  tobeMarkDecos.push({
240
238
  from: tobeCursor,
241
239
  to: tobeCursor + len,
242
240
  deco: Decoration.mark({ class: "cm-inserted-inline" })
243
241
  });
244
242
 
245
- // Line background decoration for tobe (for each line in the inserted text)
246
243
  let currentTobeLineOffset = tobeCursor;
247
244
  const tobeLines = text.split('\n');
248
245
  for (let i = 0; i < tobeLines.length; i++) {
249
- const line = this.#tobeEditorView.state.doc.lineAt(currentTobeLineOffset);
250
- tobeLineDecos.push({
251
- from: line.from,
252
- to: line.to,
253
- deco: Decoration.line({ class: "cm-inserted-line-bg" })
254
- });
255
- currentTobeLineOffset += tobeLines[i].length + 1; // Move to the start of the next line segment
246
+ // ⭐️ 중요: lineAt() 호출 전에 유효한 문서 범위 내에 있는지 확인
247
+ if (currentTobeLineOffset < this.#tobeEditorView.state.doc.length) {
248
+ const line = this.#tobeEditorView.state.doc.lineAt(currentTobeLineOffset);
249
+ tobeLineDecos.push({
250
+ from: line.from,
251
+ to: line.to,
252
+ deco: Decoration.line({ class: "cm-inserted-line-bg" })
253
+ });
254
+ }
255
+ // 다음 줄의 시작 위치 계산. 마지막 줄이 아니면 +1 (개행문자)
256
+ currentTobeLineOffset += tobeLines[i].length + (i < tobeLines.length -1 ? 1 : 0);
257
+ // 만약 마지막 줄이 비어있다면, 더 이상 진행하지 않도록 방지
258
+ if (i === tobeLines.length - 1 && tobeLines[i].length === 0 && text.endsWith('\n') === false) {
259
+ // 마지막 줄이 빈 줄이고 텍스트가 개행으로 끝나지 않으면 (오프셋이 더 이상 증가할 필요 없음)
260
+ break;
261
+ }
256
262
  }
257
263
 
258
264
  tobeCursor += len;
259
265
  break;
260
266
 
261
267
  case diff_match_patch.DIFF_DELETE: // Deleted text
262
- // Inline mark decoration for asis
263
268
  asisMarkDecos.push({
264
269
  from: asisCursor,
265
270
  to: asisCursor + len,
266
271
  deco: Decoration.mark({ class: "cm-deleted-inline" })
267
272
  });
268
273
 
269
- // Line background decoration for asis (for each line in the deleted text)
270
274
  let currentAsisLineOffset = asisCursor;
271
275
  const asisLines = text.split('\n');
272
276
  for (let i = 0; i < asisLines.length; i++) {
273
- const line = this.#asisEditorView.state.doc.lineAt(currentAsisLineOffset);
274
- asisLineDecos.push({
275
- from: line.from,
276
- to: line.to,
277
- deco: Decoration.line({ class: "cm-deleted-line-bg" })
278
- });
279
- currentAsisLineOffset += asisLines[i].length + 1;
277
+ // ⭐️ 중요: lineAt() 호출 전에 유효한 문서 범위 내에 있는지 확인
278
+ if (currentAsisLineOffset < this.#asisEditorView.state.doc.length) {
279
+ const line = this.#asisEditorView.state.doc.lineAt(currentAsisLineOffset);
280
+ asisLineDecos.push({
281
+ from: line.from,
282
+ to: line.to,
283
+ deco: Decoration.line({ class: "cm-deleted-line-bg" })
284
+ });
285
+ }
286
+ currentAsisLineOffset += asisLines[i].length + (i < asisLines.length -1 ? 1 : 0);
287
+ if (i === asisLines.length - 1 && asisLines[i].length === 0 && text.endsWith('\n') === false) {
288
+ break;
289
+ }
280
290
  }
281
291
 
282
292
  asisCursor += len;
@@ -289,14 +299,13 @@ export class IdeDiff extends HTMLElement {
289
299
  }
290
300
  }
291
301
 
292
- // Sort all collections by 'from' position
293
- // Although separating builders helps, sorting is still a good practice.
302
+ // Sort all collections by 'from' position (항상 좋은 습관)
294
303
  asisLineDecos.sort((a, b) => a.from - b.from);
295
304
  asisMarkDecos.sort((a, b) => a.from - b.from);
296
305
  tobeLineDecos.sort((a, b) => a.from - b.from);
297
306
  tobeMarkDecos.sort((a, b) => a.from - b.from);
298
307
 
299
- // Build separate RangeSets for lines and marks for ASIS editor
308
+ // ASIS 에디터용 마크 데코레이션을 위한 별도 RangeSetBuilder 생성
300
309
  const asisLineBuilder = new RangeSetBuilder();
301
310
  for (const { from, to, deco } of asisLineDecos) {
302
311
  asisLineBuilder.add(from, to, deco);
@@ -306,14 +315,12 @@ export class IdeDiff extends HTMLElement {
306
315
  asisMarkBuilder.add(from, to, deco);
307
316
  }
308
317
 
309
- // Combine line and mark RangeSets for ASIS editor
310
- // The `RangeSet.join()` static method is used to combine multiple RangeSets.
318
+ // ASIS 에디터용 마크 RangeSet 결합
311
319
  const finalAsisDecorations = asisLineBuilder.finish().update({
312
- add: asisMarkBuilder.finish().children // Combine children of mark builder's RangeSet
320
+ add: asisMarkBuilder.finish().children
313
321
  });
314
322
 
315
-
316
- // Build separate RangeSets for lines and marks for TOBE editor
323
+ // TOBE 에디터용 줄 및 마크 데코레이션을 위한 별도 RangeSetBuilder 생성
317
324
  const tobeLineBuilder = new RangeSetBuilder();
318
325
  for (const { from, to, deco } of tobeLineDecos) {
319
326
  tobeLineBuilder.add(from, to, deco);
@@ -323,13 +330,12 @@ export class IdeDiff extends HTMLElement {
323
330
  tobeMarkBuilder.add(from, to, deco);
324
331
  }
325
332
 
326
- // Combine line and mark RangeSets for TOBE editor
333
+ // TOBE 에디터용 마크 RangeSet 결합
327
334
  const finalTobeDecorations = tobeLineBuilder.finish().update({
328
335
  add: tobeMarkBuilder.finish().children
329
336
  });
330
337
 
331
-
332
- // Dispatch effects to update decorations
338
+ // 데코레이션 업데이트를 위한 Effect 디스패치
333
339
  this.#asisEditorView.dispatch({
334
340
  effects: setAsisDecorationsEffect.of(finalAsisDecorations)
335
341
  });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ide-assi",
3
3
  "type": "module",
4
- "version": "0.344.0",
4
+ "version": "0.346.0",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "exports": {
@@ -221,7 +221,6 @@ export class IdeDiff extends HTMLElement {
221
221
  const diffs = dmp.diff_main(asisSrc, tobeSrc);
222
222
  dmp.diff_cleanupSemantic(diffs);
223
223
 
224
- // Separate collections for line decorations and mark decorations
225
224
  const asisLineDecos = [];
226
225
  const asisMarkDecos = [];
227
226
  const tobeLineDecos = [];
@@ -235,48 +234,59 @@ export class IdeDiff extends HTMLElement {
235
234
 
236
235
  switch (op) {
237
236
  case diff_match_patch.DIFF_INSERT: // Added text
238
- // Inline mark decoration for tobe
239
237
  tobeMarkDecos.push({
240
238
  from: tobeCursor,
241
239
  to: tobeCursor + len,
242
240
  deco: Decoration.mark({ class: "cm-inserted-inline" })
243
241
  });
244
242
 
245
- // Line background decoration for tobe (for each line in the inserted text)
246
243
  let currentTobeLineOffset = tobeCursor;
247
244
  const tobeLines = text.split('\n');
248
245
  for (let i = 0; i < tobeLines.length; i++) {
249
- const line = this.#tobeEditorView.state.doc.lineAt(currentTobeLineOffset);
250
- tobeLineDecos.push({
251
- from: line.from,
252
- to: line.to,
253
- deco: Decoration.line({ class: "cm-inserted-line-bg" })
254
- });
255
- currentTobeLineOffset += tobeLines[i].length + 1; // Move to the start of the next line segment
246
+ // ⭐️ 중요: lineAt() 호출 전에 유효한 문서 범위 내에 있는지 확인
247
+ if (currentTobeLineOffset < this.#tobeEditorView.state.doc.length) {
248
+ const line = this.#tobeEditorView.state.doc.lineAt(currentTobeLineOffset);
249
+ tobeLineDecos.push({
250
+ from: line.from,
251
+ to: line.to,
252
+ deco: Decoration.line({ class: "cm-inserted-line-bg" })
253
+ });
254
+ }
255
+ // 다음 줄의 시작 위치 계산. 마지막 줄이 아니면 +1 (개행문자)
256
+ currentTobeLineOffset += tobeLines[i].length + (i < tobeLines.length -1 ? 1 : 0);
257
+ // 만약 마지막 줄이 비어있다면, 더 이상 진행하지 않도록 방지
258
+ if (i === tobeLines.length - 1 && tobeLines[i].length === 0 && text.endsWith('\n') === false) {
259
+ // 마지막 줄이 빈 줄이고 텍스트가 개행으로 끝나지 않으면 (오프셋이 더 이상 증가할 필요 없음)
260
+ break;
261
+ }
256
262
  }
257
263
 
258
264
  tobeCursor += len;
259
265
  break;
260
266
 
261
267
  case diff_match_patch.DIFF_DELETE: // Deleted text
262
- // Inline mark decoration for asis
263
268
  asisMarkDecos.push({
264
269
  from: asisCursor,
265
270
  to: asisCursor + len,
266
271
  deco: Decoration.mark({ class: "cm-deleted-inline" })
267
272
  });
268
273
 
269
- // Line background decoration for asis (for each line in the deleted text)
270
274
  let currentAsisLineOffset = asisCursor;
271
275
  const asisLines = text.split('\n');
272
276
  for (let i = 0; i < asisLines.length; i++) {
273
- const line = this.#asisEditorView.state.doc.lineAt(currentAsisLineOffset);
274
- asisLineDecos.push({
275
- from: line.from,
276
- to: line.to,
277
- deco: Decoration.line({ class: "cm-deleted-line-bg" })
278
- });
279
- currentAsisLineOffset += asisLines[i].length + 1;
277
+ // ⭐️ 중요: lineAt() 호출 전에 유효한 문서 범위 내에 있는지 확인
278
+ if (currentAsisLineOffset < this.#asisEditorView.state.doc.length) {
279
+ const line = this.#asisEditorView.state.doc.lineAt(currentAsisLineOffset);
280
+ asisLineDecos.push({
281
+ from: line.from,
282
+ to: line.to,
283
+ deco: Decoration.line({ class: "cm-deleted-line-bg" })
284
+ });
285
+ }
286
+ currentAsisLineOffset += asisLines[i].length + (i < asisLines.length -1 ? 1 : 0);
287
+ if (i === asisLines.length - 1 && asisLines[i].length === 0 && text.endsWith('\n') === false) {
288
+ break;
289
+ }
280
290
  }
281
291
 
282
292
  asisCursor += len;
@@ -289,14 +299,13 @@ export class IdeDiff extends HTMLElement {
289
299
  }
290
300
  }
291
301
 
292
- // Sort all collections by 'from' position
293
- // Although separating builders helps, sorting is still a good practice.
302
+ // Sort all collections by 'from' position (항상 좋은 습관)
294
303
  asisLineDecos.sort((a, b) => a.from - b.from);
295
304
  asisMarkDecos.sort((a, b) => a.from - b.from);
296
305
  tobeLineDecos.sort((a, b) => a.from - b.from);
297
306
  tobeMarkDecos.sort((a, b) => a.from - b.from);
298
307
 
299
- // Build separate RangeSets for lines and marks for ASIS editor
308
+ // ASIS 에디터용 마크 데코레이션을 위한 별도 RangeSetBuilder 생성
300
309
  const asisLineBuilder = new RangeSetBuilder();
301
310
  for (const { from, to, deco } of asisLineDecos) {
302
311
  asisLineBuilder.add(from, to, deco);
@@ -306,14 +315,12 @@ export class IdeDiff extends HTMLElement {
306
315
  asisMarkBuilder.add(from, to, deco);
307
316
  }
308
317
 
309
- // Combine line and mark RangeSets for ASIS editor
310
- // The `RangeSet.join()` static method is used to combine multiple RangeSets.
318
+ // ASIS 에디터용 마크 RangeSet 결합
311
319
  const finalAsisDecorations = asisLineBuilder.finish().update({
312
- add: asisMarkBuilder.finish().children // Combine children of mark builder's RangeSet
320
+ add: asisMarkBuilder.finish().children
313
321
  });
314
322
 
315
-
316
- // Build separate RangeSets for lines and marks for TOBE editor
323
+ // TOBE 에디터용 줄 및 마크 데코레이션을 위한 별도 RangeSetBuilder 생성
317
324
  const tobeLineBuilder = new RangeSetBuilder();
318
325
  for (const { from, to, deco } of tobeLineDecos) {
319
326
  tobeLineBuilder.add(from, to, deco);
@@ -323,13 +330,12 @@ export class IdeDiff extends HTMLElement {
323
330
  tobeMarkBuilder.add(from, to, deco);
324
331
  }
325
332
 
326
- // Combine line and mark RangeSets for TOBE editor
333
+ // TOBE 에디터용 마크 RangeSet 결합
327
334
  const finalTobeDecorations = tobeLineBuilder.finish().update({
328
335
  add: tobeMarkBuilder.finish().children
329
336
  });
330
337
 
331
-
332
- // Dispatch effects to update decorations
338
+ // 데코레이션 업데이트를 위한 Effect 디스패치
333
339
  this.#asisEditorView.dispatch({
334
340
  effects: setAsisDecorationsEffect.of(finalAsisDecorations)
335
341
  });