ide-assi 0.435.0 → 0.436.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.
@@ -234970,7 +234970,7 @@ class IdeDiff extends HTMLElement {
234970
234970
  extensions: [
234971
234971
  basicExtensions,
234972
234972
  this.#languageCompartment.of(javascript()), // 초기 언어 설정
234973
- EditorState.readOnly.of(true),
234973
+ //EditorState.readOnly.of(true),
234974
234974
  tobeDiffDecorations, // TOBE Diff 데코레이션 필드
234975
234975
  EditorView.updateListener.of((update) => {
234976
234976
  if (update.view.contentDOM.firstChild && !update.view._initialTobeContentLoaded) {
@@ -235065,9 +235065,17 @@ class IdeDiff extends HTMLElement {
235065
235065
  const deletedLineDeco = Decoration.line({ class: "cm-deleted-line-bg" });
235066
235066
  // const changedLineDeco = Decoration.line({ class: "cm-changed-line-bg" }); // 필요하다면
235067
235067
 
235068
+ // ⭐️ IdeDiff 인스턴스에 대한 참조를 위젯에 넘겨주기 위해 임시 변수 사용
235069
+ // 실제로는 Closure나 Bound method로 넘겨줄 수 있음
235070
+ const currentInstance = this;
235071
+
235068
235072
  for (const [op, text] of diffs) {
235069
235073
  const len = text.length;
235070
235074
 
235075
+ // ⭐️ 해당 diff 청크의 시작 오프셋을 저장 (버튼 위젯 위치 결정용)
235076
+ const currentAsisOffset = asisCursor;
235077
+ const currentTobeOffset = tobeCursor;
235078
+
235071
235079
  switch (op) {
235072
235080
  case diffMatchPatchExports.diff_match_patch.DIFF_INSERT:
235073
235081
  console.log(diffMatchPatchExports.diff_match_patch.DIFF_INSERT, text);
@@ -235086,6 +235094,22 @@ class IdeDiff extends HTMLElement {
235086
235094
  }
235087
235095
  tobeCursor += tobeLines[i].length + (i < tobeLines.length - 1 ? 1 : 0);
235088
235096
  }
235097
+
235098
+ tobeLineBuilder.add(
235099
+ currentTobeOffset, // 이 Diff 청크의 시작 오프셋
235100
+ currentTobeOffset,
235101
+ Decoration.widget({
235102
+ widget: // #applyDiffDecorations 내 MergeButtonWidget 생성 시
235103
+ new MergeButtonWidget(
235104
+ true, // ASIS 쪽 버튼 (적용)
235105
+ text, // 적용할 텍스트
235106
+ currentInstance.#tobeEditorView, // 적용 대상 에디터
235107
+ { from: currentAsisOffset, to: currentAsisOffset + text.length }, // ⭐️ diffRange 전달
235108
+ currentInstance // ⭐️ IdeDiff 인스턴스 전달
235109
+ ),
235110
+ side: 1 // 텍스트 뒤에 삽입
235111
+ })
235112
+ );
235089
235113
  break;
235090
235114
 
235091
235115
  case diffMatchPatchExports.diff_match_patch.DIFF_DELETE:
@@ -235097,6 +235121,21 @@ class IdeDiff extends HTMLElement {
235097
235121
  }
235098
235122
  asisCursor += asisLines[i].length + (i < asisLines.length - 1 ? 1 : 0);
235099
235123
  }
235124
+
235125
+ // ⭐️ ASIS 에디터에서 삭제된 청크의 경우, ASIS 쪽에 적용 버튼 (TOBE로 적용) 추가
235126
+ asisLineBuilder.add(
235127
+ currentAsisOffset, // 이 Diff 청크의 시작 오프셋
235128
+ currentAsisOffset,
235129
+ Decoration.widget({
235130
+ widget: new MergeButtonWidget(
235131
+ true, // ASIS 쪽 버튼 (적용)
235132
+ text, // 적용할 텍스트 (이 경우 ASIS에서 가져올 내용)
235133
+ currentInstance.#tobeEditorView // 적용 대상은 TOBE 에디터
235134
+ ),
235135
+ side: 1 // 텍스트 뒤에 삽입
235136
+ })
235137
+ );
235138
+
235100
235139
  break;
235101
235140
 
235102
235141
  case diffMatchPatchExports.diff_match_patch.DIFF_EQUAL:
@@ -235116,6 +235155,21 @@ class IdeDiff extends HTMLElement {
235116
235155
  };
235117
235156
  };
235118
235157
 
235158
+ // IdeDiff 클래스 내부에 변경 후 Diff를 다시 계산하는 메서드 추가
235159
+ recalculateDiff = () => {
235160
+ const asisDoc = this.#asisEditorView.state.doc.toString();
235161
+ const tobeDoc = this.#tobeEditorView.state.doc.toString();
235162
+
235163
+ const { asisDecorations, tobeDecorations } = this.#applyDiffDecorations(asisDoc, tobeDoc);
235164
+
235165
+ this.#asisEditorView.dispatch({
235166
+ effects: [setAsisDecorationsEffect.of(asisDecorations)]
235167
+ });
235168
+ this.#tobeEditorView.dispatch({
235169
+ effects: [setTobeDecorationsEffect.of(tobeDecorations)]
235170
+ });
235171
+ };
235172
+
235119
235173
  initialize = (src1, src2, language = 'javascript') => {
235120
235174
  if (!this.#asisEditorView || !this.#tobeEditorView) {
235121
235175
  console.warn('CodeMirror Editors not initialized yet.');
@@ -235164,6 +235218,71 @@ class IdeDiff extends HTMLElement {
235164
235218
  };
235165
235219
  }
235166
235220
 
235221
+ // IdeDiff 클래스 외부 (파일 상단 or 하단)에 추가
235222
+ class MergeButtonWidget extends WidgetType {
235223
+ constructor(isAsis, textToApply, targetEditorView, diffRange, hostComponent) {
235224
+ super();
235225
+ this.isAsis = isAsis; // ASIS 쪽 버튼인지 (true) TOBE 쪽 버튼인지 (false)
235226
+ this.textToApply = textToApply; // 적용할 텍스트
235227
+ this.targetEditorView = targetEditorView; // 텍스트를 적용할 에디터 뷰
235228
+ this.diffRange = diffRange; // ⭐️ 추가된 속성
235229
+ this.hostComponent = hostComponent; // ⭐️ IdeDiff 인스턴스 참조
235230
+ }
235231
+
235232
+ // 위젯이 차지할 공간을 텍스트 줄에 할당할지 여부. false로 설정하여 버튼이 줄 사이에 끼어들지 않도록 함.
235233
+ eq(other) { return false; }
235234
+
235235
+ // 위젯의 DOM 요소를 생성합니다.
235236
+ toDOM(view) {
235237
+ const button = document.createElement("button");
235238
+ button.className = `cm-merge-button ${this.isAsis ? 'accept' : 'revert'}`;
235239
+ button.textContent = this.isAsis ? "→ 적용" : "← 되돌리기"; // 버튼 텍스트
235240
+
235241
+ // 클릭 이벤트 핸들러
235242
+ button.addEventListener("click", () => {
235243
+ // 이 로직은 나중에 구현할 `applyChanges` 메서드를 호출할 것입니다.
235244
+ // 지금은 콘솔에 로그만 남깁니다.
235245
+ console.log(`버튼 클릭: ${this.isAsis ? 'ASIS -> TOBE' : 'TOBE -> ASIS'}`, this.textToApply);
235246
+
235247
+ // 실제 변경 로직 (아래 applyChanges 메서드 구현 후 주석 해제)
235248
+ this.applyChanges(this.textToApply, this.targetEditorView);
235249
+ });
235250
+
235251
+ const container = document.createElement("div");
235252
+ container.className = "cm-merge-button-container";
235253
+ container.appendChild(button);
235254
+ return container;
235255
+ }
235256
+
235257
+ // 실제 변경 적용 로직
235258
+ applyChanges(text, editorView) {
235259
+ if (!editorView || !this.diffRange) {
235260
+ console.error("Target editor view or diffRange is undefined.");
235261
+ return;
235262
+ }
235263
+
235264
+ // ⭐️ 해당 오프셋 범위의 내용을 교체 (삽입 또는 삭제)
235265
+ editorView.dispatch({
235266
+ changes: {
235267
+ from: this.diffRange.from,
235268
+ to: this.diffRange.to, // 삭제될 범위
235269
+ insert: text // 삽입될 내용
235270
+ }
235271
+ });
235272
+
235273
+ // 변경 후 Diff를 다시 계산하고 데코레이션을 업데이트해야 합니다.
235274
+ // this.hostComponent.recalculateDiff(); 와 같은 메서드를 호출해야 함.
235275
+ // 이 부분은 IdeDiff 클래스 내에서 구현해야 합니다.
235276
+ // 일단은 콘솔 로그와 함께 작동하는지 확인합니다.
235277
+ console.log("Changes applied and diff recalculation needed!");
235278
+
235279
+ // 변경 후 Diff를 다시 계산하고 데코레이션을 업데이트합니다.
235280
+ this.hostComponent.recalculateDiff(); // ⭐️ hostComponent를 통해 메서드 호출
235281
+ }
235282
+
235283
+
235284
+ }
235285
+
235167
235286
  customElements.define("ide-diff", IdeDiff);
235168
235287
 
235169
235288
  //import "./components/ideAssi.js";
@@ -234966,7 +234966,7 @@ class IdeDiff extends HTMLElement {
234966
234966
  extensions: [
234967
234967
  basicExtensions,
234968
234968
  this.#languageCompartment.of(javascript()), // 초기 언어 설정
234969
- EditorState.readOnly.of(true),
234969
+ //EditorState.readOnly.of(true),
234970
234970
  tobeDiffDecorations, // TOBE Diff 데코레이션 필드
234971
234971
  EditorView.updateListener.of((update) => {
234972
234972
  if (update.view.contentDOM.firstChild && !update.view._initialTobeContentLoaded) {
@@ -235061,9 +235061,17 @@ class IdeDiff extends HTMLElement {
235061
235061
  const deletedLineDeco = Decoration.line({ class: "cm-deleted-line-bg" });
235062
235062
  // const changedLineDeco = Decoration.line({ class: "cm-changed-line-bg" }); // 필요하다면
235063
235063
 
235064
+ // ⭐️ IdeDiff 인스턴스에 대한 참조를 위젯에 넘겨주기 위해 임시 변수 사용
235065
+ // 실제로는 Closure나 Bound method로 넘겨줄 수 있음
235066
+ const currentInstance = this;
235067
+
235064
235068
  for (const [op, text] of diffs) {
235065
235069
  const len = text.length;
235066
235070
 
235071
+ // ⭐️ 해당 diff 청크의 시작 오프셋을 저장 (버튼 위젯 위치 결정용)
235072
+ const currentAsisOffset = asisCursor;
235073
+ const currentTobeOffset = tobeCursor;
235074
+
235067
235075
  switch (op) {
235068
235076
  case diffMatchPatchExports.diff_match_patch.DIFF_INSERT:
235069
235077
  console.log(diffMatchPatchExports.diff_match_patch.DIFF_INSERT, text);
@@ -235082,6 +235090,22 @@ class IdeDiff extends HTMLElement {
235082
235090
  }
235083
235091
  tobeCursor += tobeLines[i].length + (i < tobeLines.length - 1 ? 1 : 0);
235084
235092
  }
235093
+
235094
+ tobeLineBuilder.add(
235095
+ currentTobeOffset, // 이 Diff 청크의 시작 오프셋
235096
+ currentTobeOffset,
235097
+ Decoration.widget({
235098
+ widget: // #applyDiffDecorations 내 MergeButtonWidget 생성 시
235099
+ new MergeButtonWidget(
235100
+ true, // ASIS 쪽 버튼 (적용)
235101
+ text, // 적용할 텍스트
235102
+ currentInstance.#tobeEditorView, // 적용 대상 에디터
235103
+ { from: currentAsisOffset, to: currentAsisOffset + text.length }, // ⭐️ diffRange 전달
235104
+ currentInstance // ⭐️ IdeDiff 인스턴스 전달
235105
+ ),
235106
+ side: 1 // 텍스트 뒤에 삽입
235107
+ })
235108
+ );
235085
235109
  break;
235086
235110
 
235087
235111
  case diffMatchPatchExports.diff_match_patch.DIFF_DELETE:
@@ -235093,6 +235117,21 @@ class IdeDiff extends HTMLElement {
235093
235117
  }
235094
235118
  asisCursor += asisLines[i].length + (i < asisLines.length - 1 ? 1 : 0);
235095
235119
  }
235120
+
235121
+ // ⭐️ ASIS 에디터에서 삭제된 청크의 경우, ASIS 쪽에 적용 버튼 (TOBE로 적용) 추가
235122
+ asisLineBuilder.add(
235123
+ currentAsisOffset, // 이 Diff 청크의 시작 오프셋
235124
+ currentAsisOffset,
235125
+ Decoration.widget({
235126
+ widget: new MergeButtonWidget(
235127
+ true, // ASIS 쪽 버튼 (적용)
235128
+ text, // 적용할 텍스트 (이 경우 ASIS에서 가져올 내용)
235129
+ currentInstance.#tobeEditorView // 적용 대상은 TOBE 에디터
235130
+ ),
235131
+ side: 1 // 텍스트 뒤에 삽입
235132
+ })
235133
+ );
235134
+
235096
235135
  break;
235097
235136
 
235098
235137
  case diffMatchPatchExports.diff_match_patch.DIFF_EQUAL:
@@ -235112,6 +235151,21 @@ class IdeDiff extends HTMLElement {
235112
235151
  };
235113
235152
  };
235114
235153
 
235154
+ // IdeDiff 클래스 내부에 변경 후 Diff를 다시 계산하는 메서드 추가
235155
+ recalculateDiff = () => {
235156
+ const asisDoc = this.#asisEditorView.state.doc.toString();
235157
+ const tobeDoc = this.#tobeEditorView.state.doc.toString();
235158
+
235159
+ const { asisDecorations, tobeDecorations } = this.#applyDiffDecorations(asisDoc, tobeDoc);
235160
+
235161
+ this.#asisEditorView.dispatch({
235162
+ effects: [setAsisDecorationsEffect.of(asisDecorations)]
235163
+ });
235164
+ this.#tobeEditorView.dispatch({
235165
+ effects: [setTobeDecorationsEffect.of(tobeDecorations)]
235166
+ });
235167
+ };
235168
+
235115
235169
  initialize = (src1, src2, language = 'javascript') => {
235116
235170
  if (!this.#asisEditorView || !this.#tobeEditorView) {
235117
235171
  console.warn('CodeMirror Editors not initialized yet.');
@@ -235160,6 +235214,71 @@ class IdeDiff extends HTMLElement {
235160
235214
  };
235161
235215
  }
235162
235216
 
235217
+ // IdeDiff 클래스 외부 (파일 상단 or 하단)에 추가
235218
+ class MergeButtonWidget extends WidgetType {
235219
+ constructor(isAsis, textToApply, targetEditorView, diffRange, hostComponent) {
235220
+ super();
235221
+ this.isAsis = isAsis; // ASIS 쪽 버튼인지 (true) TOBE 쪽 버튼인지 (false)
235222
+ this.textToApply = textToApply; // 적용할 텍스트
235223
+ this.targetEditorView = targetEditorView; // 텍스트를 적용할 에디터 뷰
235224
+ this.diffRange = diffRange; // ⭐️ 추가된 속성
235225
+ this.hostComponent = hostComponent; // ⭐️ IdeDiff 인스턴스 참조
235226
+ }
235227
+
235228
+ // 위젯이 차지할 공간을 텍스트 줄에 할당할지 여부. false로 설정하여 버튼이 줄 사이에 끼어들지 않도록 함.
235229
+ eq(other) { return false; }
235230
+
235231
+ // 위젯의 DOM 요소를 생성합니다.
235232
+ toDOM(view) {
235233
+ const button = document.createElement("button");
235234
+ button.className = `cm-merge-button ${this.isAsis ? 'accept' : 'revert'}`;
235235
+ button.textContent = this.isAsis ? "→ 적용" : "← 되돌리기"; // 버튼 텍스트
235236
+
235237
+ // 클릭 이벤트 핸들러
235238
+ button.addEventListener("click", () => {
235239
+ // 이 로직은 나중에 구현할 `applyChanges` 메서드를 호출할 것입니다.
235240
+ // 지금은 콘솔에 로그만 남깁니다.
235241
+ console.log(`버튼 클릭: ${this.isAsis ? 'ASIS -> TOBE' : 'TOBE -> ASIS'}`, this.textToApply);
235242
+
235243
+ // 실제 변경 로직 (아래 applyChanges 메서드 구현 후 주석 해제)
235244
+ this.applyChanges(this.textToApply, this.targetEditorView);
235245
+ });
235246
+
235247
+ const container = document.createElement("div");
235248
+ container.className = "cm-merge-button-container";
235249
+ container.appendChild(button);
235250
+ return container;
235251
+ }
235252
+
235253
+ // 실제 변경 적용 로직
235254
+ applyChanges(text, editorView) {
235255
+ if (!editorView || !this.diffRange) {
235256
+ console.error("Target editor view or diffRange is undefined.");
235257
+ return;
235258
+ }
235259
+
235260
+ // ⭐️ 해당 오프셋 범위의 내용을 교체 (삽입 또는 삭제)
235261
+ editorView.dispatch({
235262
+ changes: {
235263
+ from: this.diffRange.from,
235264
+ to: this.diffRange.to, // 삭제될 범위
235265
+ insert: text // 삽입될 내용
235266
+ }
235267
+ });
235268
+
235269
+ // 변경 후 Diff를 다시 계산하고 데코레이션을 업데이트해야 합니다.
235270
+ // this.hostComponent.recalculateDiff(); 와 같은 메서드를 호출해야 함.
235271
+ // 이 부분은 IdeDiff 클래스 내에서 구현해야 합니다.
235272
+ // 일단은 콘솔 로그와 함께 작동하는지 확인합니다.
235273
+ console.log("Changes applied and diff recalculation needed!");
235274
+
235275
+ // 변경 후 Diff를 다시 계산하고 데코레이션을 업데이트합니다.
235276
+ this.hostComponent.recalculateDiff(); // ⭐️ hostComponent를 통해 메서드 호출
235277
+ }
235278
+
235279
+
235280
+ }
235281
+
235163
235282
  customElements.define("ide-diff", IdeDiff);
235164
235283
 
235165
235284
  //import "./components/ideAssi.js";
@@ -4,7 +4,7 @@ import ninegrid from "ninegrid2";
4
4
  import {
5
5
  EditorView, lineNumbers, highlightSpecialChars, drawSelection,
6
6
  dropCursor, keymap, highlightActiveLine, highlightActiveLineGutter,
7
- Decoration
7
+ Decoration, WidgetType
8
8
  } from "@codemirror/view";
9
9
  import {
10
10
  EditorState, Compartment, StateField,
@@ -178,7 +178,7 @@ export class IdeDiff extends HTMLElement {
178
178
  extensions: [
179
179
  basicExtensions,
180
180
  this.#languageCompartment.of(javascript()), // 초기 언어 설정
181
- EditorState.readOnly.of(true),
181
+ //EditorState.readOnly.of(true),
182
182
  tobeDiffDecorations, // TOBE Diff 데코레이션 필드
183
183
  EditorView.updateListener.of((update) => {
184
184
  if (update.view.contentDOM.firstChild && !update.view._initialTobeContentLoaded) {
@@ -273,9 +273,17 @@ export class IdeDiff extends HTMLElement {
273
273
  const deletedLineDeco = Decoration.line({ class: "cm-deleted-line-bg" });
274
274
  // const changedLineDeco = Decoration.line({ class: "cm-changed-line-bg" }); // 필요하다면
275
275
 
276
+ // ⭐️ IdeDiff 인스턴스에 대한 참조를 위젯에 넘겨주기 위해 임시 변수 사용
277
+ // 실제로는 Closure나 Bound method로 넘겨줄 수 있음
278
+ const currentInstance = this;
279
+
276
280
  for (const [op, text] of diffs) {
277
281
  const len = text.length;
278
282
 
283
+ // ⭐️ 해당 diff 청크의 시작 오프셋을 저장 (버튼 위젯 위치 결정용)
284
+ const currentAsisOffset = asisCursor;
285
+ const currentTobeOffset = tobeCursor;
286
+
279
287
  switch (op) {
280
288
  case diff_match_patch.DIFF_INSERT:
281
289
  console.log(diff_match_patch.DIFF_INSERT, text);
@@ -294,6 +302,22 @@ export class IdeDiff extends HTMLElement {
294
302
  }
295
303
  tobeCursor += tobeLines[i].length + (i < tobeLines.length - 1 ? 1 : 0);
296
304
  }
305
+
306
+ tobeLineBuilder.add(
307
+ currentTobeOffset, // 이 Diff 청크의 시작 오프셋
308
+ currentTobeOffset,
309
+ Decoration.widget({
310
+ widget: // #applyDiffDecorations 내 MergeButtonWidget 생성 시
311
+ new MergeButtonWidget(
312
+ true, // ASIS 쪽 버튼 (적용)
313
+ text, // 적용할 텍스트
314
+ currentInstance.#tobeEditorView, // 적용 대상 에디터
315
+ { from: currentAsisOffset, to: currentAsisOffset + text.length }, // ⭐️ diffRange 전달
316
+ currentInstance // ⭐️ IdeDiff 인스턴스 전달
317
+ ),
318
+ side: 1 // 텍스트 뒤에 삽입
319
+ })
320
+ );
297
321
  break;
298
322
 
299
323
  case diff_match_patch.DIFF_DELETE:
@@ -305,6 +329,21 @@ export class IdeDiff extends HTMLElement {
305
329
  }
306
330
  asisCursor += asisLines[i].length + (i < asisLines.length - 1 ? 1 : 0);
307
331
  }
332
+
333
+ // ⭐️ ASIS 에디터에서 삭제된 청크의 경우, ASIS 쪽에 적용 버튼 (TOBE로 적용) 추가
334
+ asisLineBuilder.add(
335
+ currentAsisOffset, // 이 Diff 청크의 시작 오프셋
336
+ currentAsisOffset,
337
+ Decoration.widget({
338
+ widget: new MergeButtonWidget(
339
+ true, // ASIS 쪽 버튼 (적용)
340
+ text, // 적용할 텍스트 (이 경우 ASIS에서 가져올 내용)
341
+ currentInstance.#tobeEditorView // 적용 대상은 TOBE 에디터
342
+ ),
343
+ side: 1 // 텍스트 뒤에 삽입
344
+ })
345
+ );
346
+
308
347
  break;
309
348
 
310
349
  case diff_match_patch.DIFF_EQUAL:
@@ -324,6 +363,21 @@ export class IdeDiff extends HTMLElement {
324
363
  };
325
364
  };
326
365
 
366
+ // IdeDiff 클래스 내부에 변경 후 Diff를 다시 계산하는 메서드 추가
367
+ recalculateDiff = () => {
368
+ const asisDoc = this.#asisEditorView.state.doc.toString();
369
+ const tobeDoc = this.#tobeEditorView.state.doc.toString();
370
+
371
+ const { asisDecorations, tobeDecorations } = this.#applyDiffDecorations(asisDoc, tobeDoc);
372
+
373
+ this.#asisEditorView.dispatch({
374
+ effects: [setAsisDecorationsEffect.of(asisDecorations)]
375
+ });
376
+ this.#tobeEditorView.dispatch({
377
+ effects: [setTobeDecorationsEffect.of(tobeDecorations)]
378
+ });
379
+ };
380
+
327
381
  initialize = (src1, src2, language = 'javascript') => {
328
382
  if (!this.#asisEditorView || !this.#tobeEditorView) {
329
383
  console.warn('CodeMirror Editors not initialized yet.');
@@ -372,4 +426,69 @@ export class IdeDiff extends HTMLElement {
372
426
  };
373
427
  }
374
428
 
429
+ // IdeDiff 클래스 외부 (파일 상단 or 하단)에 추가
430
+ class MergeButtonWidget extends WidgetType {
431
+ constructor(isAsis, textToApply, targetEditorView, diffRange, hostComponent) {
432
+ super();
433
+ this.isAsis = isAsis; // ASIS 쪽 버튼인지 (true) TOBE 쪽 버튼인지 (false)
434
+ this.textToApply = textToApply; // 적용할 텍스트
435
+ this.targetEditorView = targetEditorView; // 텍스트를 적용할 에디터 뷰
436
+ this.diffRange = diffRange; // ⭐️ 추가된 속성
437
+ this.hostComponent = hostComponent; // ⭐️ IdeDiff 인스턴스 참조
438
+ }
439
+
440
+ // 위젯이 차지할 공간을 텍스트 줄에 할당할지 여부. false로 설정하여 버튼이 줄 사이에 끼어들지 않도록 함.
441
+ eq(other) { return false; }
442
+
443
+ // 위젯의 DOM 요소를 생성합니다.
444
+ toDOM(view) {
445
+ const button = document.createElement("button");
446
+ button.className = `cm-merge-button ${this.isAsis ? 'accept' : 'revert'}`;
447
+ button.textContent = this.isAsis ? "→ 적용" : "← 되돌리기"; // 버튼 텍스트
448
+
449
+ // 클릭 이벤트 핸들러
450
+ button.addEventListener("click", () => {
451
+ // 이 로직은 나중에 구현할 `applyChanges` 메서드를 호출할 것입니다.
452
+ // 지금은 콘솔에 로그만 남깁니다.
453
+ console.log(`버튼 클릭: ${this.isAsis ? 'ASIS -> TOBE' : 'TOBE -> ASIS'}`, this.textToApply);
454
+
455
+ // 실제 변경 로직 (아래 applyChanges 메서드 구현 후 주석 해제)
456
+ this.applyChanges(this.textToApply, this.targetEditorView);
457
+ });
458
+
459
+ const container = document.createElement("div");
460
+ container.className = "cm-merge-button-container";
461
+ container.appendChild(button);
462
+ return container;
463
+ }
464
+
465
+ // 실제 변경 적용 로직
466
+ applyChanges(text, editorView) {
467
+ if (!editorView || !this.diffRange) {
468
+ console.error("Target editor view or diffRange is undefined.");
469
+ return;
470
+ }
471
+
472
+ // ⭐️ 해당 오프셋 범위의 내용을 교체 (삽입 또는 삭제)
473
+ editorView.dispatch({
474
+ changes: {
475
+ from: this.diffRange.from,
476
+ to: this.diffRange.to, // 삭제될 범위
477
+ insert: text // 삽입될 내용
478
+ }
479
+ });
480
+
481
+ // 변경 후 Diff를 다시 계산하고 데코레이션을 업데이트해야 합니다.
482
+ // this.hostComponent.recalculateDiff(); 와 같은 메서드를 호출해야 함.
483
+ // 이 부분은 IdeDiff 클래스 내에서 구현해야 합니다.
484
+ // 일단은 콘솔 로그와 함께 작동하는지 확인합니다.
485
+ console.log("Changes applied and diff recalculation needed!");
486
+
487
+ // 변경 후 Diff를 다시 계산하고 데코레이션을 업데이트합니다.
488
+ this.hostComponent.recalculateDiff(); // ⭐️ hostComponent를 통해 메서드 호출
489
+ }
490
+
491
+
492
+ }
493
+
375
494
  customElements.define("ide-diff", IdeDiff);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ide-assi",
3
3
  "type": "module",
4
- "version": "0.435.0",
4
+ "version": "0.436.0",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "exports": {
@@ -4,7 +4,7 @@ import ninegrid from "ninegrid2";
4
4
  import {
5
5
  EditorView, lineNumbers, highlightSpecialChars, drawSelection,
6
6
  dropCursor, keymap, highlightActiveLine, highlightActiveLineGutter,
7
- Decoration
7
+ Decoration, WidgetType
8
8
  } from "@codemirror/view";
9
9
  import {
10
10
  EditorState, Compartment, StateField,
@@ -178,7 +178,7 @@ export class IdeDiff extends HTMLElement {
178
178
  extensions: [
179
179
  basicExtensions,
180
180
  this.#languageCompartment.of(javascript()), // 초기 언어 설정
181
- EditorState.readOnly.of(true),
181
+ //EditorState.readOnly.of(true),
182
182
  tobeDiffDecorations, // TOBE Diff 데코레이션 필드
183
183
  EditorView.updateListener.of((update) => {
184
184
  if (update.view.contentDOM.firstChild && !update.view._initialTobeContentLoaded) {
@@ -273,9 +273,17 @@ export class IdeDiff extends HTMLElement {
273
273
  const deletedLineDeco = Decoration.line({ class: "cm-deleted-line-bg" });
274
274
  // const changedLineDeco = Decoration.line({ class: "cm-changed-line-bg" }); // 필요하다면
275
275
 
276
+ // ⭐️ IdeDiff 인스턴스에 대한 참조를 위젯에 넘겨주기 위해 임시 변수 사용
277
+ // 실제로는 Closure나 Bound method로 넘겨줄 수 있음
278
+ const currentInstance = this;
279
+
276
280
  for (const [op, text] of diffs) {
277
281
  const len = text.length;
278
282
 
283
+ // ⭐️ 해당 diff 청크의 시작 오프셋을 저장 (버튼 위젯 위치 결정용)
284
+ const currentAsisOffset = asisCursor;
285
+ const currentTobeOffset = tobeCursor;
286
+
279
287
  switch (op) {
280
288
  case diff_match_patch.DIFF_INSERT:
281
289
  console.log(diff_match_patch.DIFF_INSERT, text);
@@ -294,6 +302,22 @@ export class IdeDiff extends HTMLElement {
294
302
  }
295
303
  tobeCursor += tobeLines[i].length + (i < tobeLines.length - 1 ? 1 : 0);
296
304
  }
305
+
306
+ tobeLineBuilder.add(
307
+ currentTobeOffset, // 이 Diff 청크의 시작 오프셋
308
+ currentTobeOffset,
309
+ Decoration.widget({
310
+ widget: // #applyDiffDecorations 내 MergeButtonWidget 생성 시
311
+ new MergeButtonWidget(
312
+ true, // ASIS 쪽 버튼 (적용)
313
+ text, // 적용할 텍스트
314
+ currentInstance.#tobeEditorView, // 적용 대상 에디터
315
+ { from: currentAsisOffset, to: currentAsisOffset + text.length }, // ⭐️ diffRange 전달
316
+ currentInstance // ⭐️ IdeDiff 인스턴스 전달
317
+ ),
318
+ side: 1 // 텍스트 뒤에 삽입
319
+ })
320
+ );
297
321
  break;
298
322
 
299
323
  case diff_match_patch.DIFF_DELETE:
@@ -305,6 +329,21 @@ export class IdeDiff extends HTMLElement {
305
329
  }
306
330
  asisCursor += asisLines[i].length + (i < asisLines.length - 1 ? 1 : 0);
307
331
  }
332
+
333
+ // ⭐️ ASIS 에디터에서 삭제된 청크의 경우, ASIS 쪽에 적용 버튼 (TOBE로 적용) 추가
334
+ asisLineBuilder.add(
335
+ currentAsisOffset, // 이 Diff 청크의 시작 오프셋
336
+ currentAsisOffset,
337
+ Decoration.widget({
338
+ widget: new MergeButtonWidget(
339
+ true, // ASIS 쪽 버튼 (적용)
340
+ text, // 적용할 텍스트 (이 경우 ASIS에서 가져올 내용)
341
+ currentInstance.#tobeEditorView // 적용 대상은 TOBE 에디터
342
+ ),
343
+ side: 1 // 텍스트 뒤에 삽입
344
+ })
345
+ );
346
+
308
347
  break;
309
348
 
310
349
  case diff_match_patch.DIFF_EQUAL:
@@ -324,6 +363,21 @@ export class IdeDiff extends HTMLElement {
324
363
  };
325
364
  };
326
365
 
366
+ // IdeDiff 클래스 내부에 변경 후 Diff를 다시 계산하는 메서드 추가
367
+ recalculateDiff = () => {
368
+ const asisDoc = this.#asisEditorView.state.doc.toString();
369
+ const tobeDoc = this.#tobeEditorView.state.doc.toString();
370
+
371
+ const { asisDecorations, tobeDecorations } = this.#applyDiffDecorations(asisDoc, tobeDoc);
372
+
373
+ this.#asisEditorView.dispatch({
374
+ effects: [setAsisDecorationsEffect.of(asisDecorations)]
375
+ });
376
+ this.#tobeEditorView.dispatch({
377
+ effects: [setTobeDecorationsEffect.of(tobeDecorations)]
378
+ });
379
+ };
380
+
327
381
  initialize = (src1, src2, language = 'javascript') => {
328
382
  if (!this.#asisEditorView || !this.#tobeEditorView) {
329
383
  console.warn('CodeMirror Editors not initialized yet.');
@@ -372,4 +426,69 @@ export class IdeDiff extends HTMLElement {
372
426
  };
373
427
  }
374
428
 
429
+ // IdeDiff 클래스 외부 (파일 상단 or 하단)에 추가
430
+ class MergeButtonWidget extends WidgetType {
431
+ constructor(isAsis, textToApply, targetEditorView, diffRange, hostComponent) {
432
+ super();
433
+ this.isAsis = isAsis; // ASIS 쪽 버튼인지 (true) TOBE 쪽 버튼인지 (false)
434
+ this.textToApply = textToApply; // 적용할 텍스트
435
+ this.targetEditorView = targetEditorView; // 텍스트를 적용할 에디터 뷰
436
+ this.diffRange = diffRange; // ⭐️ 추가된 속성
437
+ this.hostComponent = hostComponent; // ⭐️ IdeDiff 인스턴스 참조
438
+ }
439
+
440
+ // 위젯이 차지할 공간을 텍스트 줄에 할당할지 여부. false로 설정하여 버튼이 줄 사이에 끼어들지 않도록 함.
441
+ eq(other) { return false; }
442
+
443
+ // 위젯의 DOM 요소를 생성합니다.
444
+ toDOM(view) {
445
+ const button = document.createElement("button");
446
+ button.className = `cm-merge-button ${this.isAsis ? 'accept' : 'revert'}`;
447
+ button.textContent = this.isAsis ? "→ 적용" : "← 되돌리기"; // 버튼 텍스트
448
+
449
+ // 클릭 이벤트 핸들러
450
+ button.addEventListener("click", () => {
451
+ // 이 로직은 나중에 구현할 `applyChanges` 메서드를 호출할 것입니다.
452
+ // 지금은 콘솔에 로그만 남깁니다.
453
+ console.log(`버튼 클릭: ${this.isAsis ? 'ASIS -> TOBE' : 'TOBE -> ASIS'}`, this.textToApply);
454
+
455
+ // 실제 변경 로직 (아래 applyChanges 메서드 구현 후 주석 해제)
456
+ this.applyChanges(this.textToApply, this.targetEditorView);
457
+ });
458
+
459
+ const container = document.createElement("div");
460
+ container.className = "cm-merge-button-container";
461
+ container.appendChild(button);
462
+ return container;
463
+ }
464
+
465
+ // 실제 변경 적용 로직
466
+ applyChanges(text, editorView) {
467
+ if (!editorView || !this.diffRange) {
468
+ console.error("Target editor view or diffRange is undefined.");
469
+ return;
470
+ }
471
+
472
+ // ⭐️ 해당 오프셋 범위의 내용을 교체 (삽입 또는 삭제)
473
+ editorView.dispatch({
474
+ changes: {
475
+ from: this.diffRange.from,
476
+ to: this.diffRange.to, // 삭제될 범위
477
+ insert: text // 삽입될 내용
478
+ }
479
+ });
480
+
481
+ // 변경 후 Diff를 다시 계산하고 데코레이션을 업데이트해야 합니다.
482
+ // this.hostComponent.recalculateDiff(); 와 같은 메서드를 호출해야 함.
483
+ // 이 부분은 IdeDiff 클래스 내에서 구현해야 합니다.
484
+ // 일단은 콘솔 로그와 함께 작동하는지 확인합니다.
485
+ console.log("Changes applied and diff recalculation needed!");
486
+
487
+ // 변경 후 Diff를 다시 계산하고 데코레이션을 업데이트합니다.
488
+ this.hostComponent.recalculateDiff(); // ⭐️ hostComponent를 통해 메서드 호출
489
+ }
490
+
491
+
492
+ }
493
+
375
494
  customElements.define("ide-diff", IdeDiff);