ide-assi 0.441.0 → 0.442.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.
@@ -234903,22 +234903,34 @@ const tobeButtonDecorations = StateField.define({
234903
234903
  class MergeButtonWidget extends WidgetType {
234904
234904
  constructor(isAsisButton, textToApply, targetEditorView, diffRange, hostComponent) {
234905
234905
  super();
234906
- this.isAsisButton = isAsisButton;
234907
- this.textToApply = textToApply;
234908
- this.targetEditorView = targetEditorView;
234909
- this.diffRange = diffRange;
234910
- this.hostComponent = hostComponent;
234906
+ this.isAsisButton = isAsisButton; // 이 버튼이 ASIS 에디터에 붙는 버튼인가 (true) TOBE 에디터에 붙는 버튼인가 (false)
234907
+ this.textToApply = textToApply; // 적용할 텍스트
234908
+ this.targetEditorView = targetEditorView; // 텍스트를 적용할 에디터 뷰 (상대편 에디터)
234909
+ this.diffRange = diffRange; // 대상 에디터에서 변경이 일어날 정확한 from/to 오프셋
234910
+ this.hostComponent = hostComponent; // IdeDiff 인스턴스 참조
234911
234911
  }
234912
234912
 
234913
+ // 위젯이 차지할 공간을 텍스트 줄에 할당할지 여부. false로 설정하여 버튼이 줄 사이에 끼어들지 않도록 함.
234913
234914
  eq(other) { return false; }
234914
234915
 
234916
+ // 위젯의 DOM 요소를 생성합니다.
234915
234917
  toDOM(view) {
234916
234918
  const button = document.createElement("button");
234917
- button.className = `cm-merge-button ${this.isAsisButton ? 'accept' : 'revert'}`;
234918
- button.textContent = this.isAsisButton ? "→ 적용" : "← 되돌리기";
234919
+ // SVN 기준 명칭으로 변경
234920
+ if (this.isAsisButton) {
234921
+ // ASIS (왼쪽) 에디터에 붙는 버튼: AI가 삭제한 것을 '되돌리기'
234922
+ button.className = "cm-merge-button revert"; // 'revert' 클래스 사용
234923
+ button.textContent = "← 되돌리기";
234924
+ } else {
234925
+ // TOBE (오른쪽) 에디터에 붙는 버튼: AI가 추가한 것을 '적용'
234926
+ button.className = "cm-merge-button accept"; // 'accept' 클래스 사용
234927
+ button.textContent = "→ 적용";
234928
+ }
234929
+
234919
234930
 
234931
+ // 클릭 이벤트 핸들러
234920
234932
  button.addEventListener("click", () => {
234921
- console.log(`버튼 클릭: ${this.isAsisButton ? 'ASIS -> TOBE' : 'TOBE -> ASIS'}`, this.textToApply);
234933
+ console.log(`버튼 클릭: ${this.isAsisButton ? 'ASIS (되돌리기)' : 'TOBE (적용)'}`, this.textToApply);
234922
234934
  console.log("대상 에디터:", this.targetEditorView === this.hostComponent.asisEditorView ? "ASIS" : "TOBE");
234923
234935
  console.log("대상 범위:", this.diffRange);
234924
234936
 
@@ -234931,22 +234943,13 @@ class MergeButtonWidget extends WidgetType {
234931
234943
  return container;
234932
234944
  }
234933
234945
 
234946
+ // 실제 변경 적용 로직
234934
234947
  applyChanges(text, editorView, range) {
234935
234948
  if (!editorView || !range) {
234936
234949
  console.error("Target editor view or range is undefined.", editorView, range);
234937
234950
  return;
234938
234951
  }
234939
234952
 
234940
- // 특정 줄의 시작 오프셋과 끝 오프셋을 정확히 계산하여 적용해야 합니다.
234941
- // 현재 로직은 단순 치환이므로 Diff 유형에 따라 복잡해질 수 있습니다.
234942
- // 예를 들어, TOBE에 삽입된 내용을 ASIS에서 되돌릴 경우, ASIS에서 해당 내용 길이만큼의 공백을 지워야 합니다.
234943
- // ASIS에서 삭제된 내용을 TOBE에 적용할 경우, TOBE의 해당 위치에 내용을 삽입해야 합니다.
234944
-
234945
- // CodeMirror의 Doc에서 특정 범위를 가져오는 것은 `state.sliceDoc(from, to)`
234946
- // `dmp.diff_main`의 결과는 줄 단위로 매핑된 문자열이므로,
234947
- // 실제 오프셋 계산 및 적용 로직은 더 정교해야 합니다.
234948
- // 지금은 임시로 range.from, range.to를 사용합니다.
234949
-
234950
234953
  editorView.dispatch({
234951
234954
  changes: {
234952
234955
  from: range.from,
@@ -234974,9 +234977,14 @@ class IdeDiff extends HTMLElement {
234974
234977
  _asisScrollHandler = null;
234975
234978
  _tobeScrollHandler = null;
234976
234979
 
234980
+ // MergeButtonWidget에서 접근할 수 있도록 Getter를 공개합니다.
234977
234981
  get asisEditorView() {
234978
234982
  return this.#asisEditorView;
234979
- };
234983
+ }
234984
+ get tobeEditorView() {
234985
+ return this.#tobeEditorView;
234986
+ }
234987
+
234980
234988
 
234981
234989
  constructor() {
234982
234990
  super();
@@ -234986,7 +234994,9 @@ class IdeDiff extends HTMLElement {
234986
234994
  connectedCallback() {
234987
234995
  this.shadowRoot.innerHTML = `
234988
234996
  <style>
234997
+ /* ninegrid CSS 및 필요한 기본 스타일 임포트 */
234989
234998
  @import "https://cdn.jsdelivr.net/npm/ninegrid@${ninegrid.version}/dist/css/ideDiff.css";
234999
+ /* 새로 만든 ideDiff.css 파일 임포트 */
234990
235000
  ${ninegrid.getCustomPath(this, "ideDiff.css")}
234991
235001
  </style>
234992
235002
 
@@ -235057,9 +235067,9 @@ class IdeDiff extends HTMLElement {
235057
235067
  extensions: [
235058
235068
  basicExtensions,
235059
235069
  this.#languageCompartment.of(javascript()),
235060
- EditorState.readOnly.of(true),
235070
+ EditorState.readOnly.of(true), // ASIS는 읽기 전용 유지 (원본 소스)
235061
235071
  asisDiffDecorations,
235062
- asisButtonDecorations, // ⭐️ 새로운 StateField 추가
235072
+ asisButtonDecorations,
235063
235073
  EditorView.updateListener.of((update) => {
235064
235074
  if (update.view.contentDOM.firstChild && !update.view._initialAsisContentLoaded) {
235065
235075
  update.view._initialAsisContentLoaded = true;
@@ -235077,8 +235087,9 @@ class IdeDiff extends HTMLElement {
235077
235087
  extensions: [
235078
235088
  basicExtensions,
235079
235089
  this.#languageCompartment.of(javascript()),
235090
+ // EditorState.readOnly.of(true), // TOBE는 AI 추천 소스이므로 편집 가능 (혹은 ASIS로만 적용)
235080
235091
  tobeDiffDecorations,
235081
- tobeButtonDecorations, // ⭐️ 새로운 StateField 추가
235092
+ tobeButtonDecorations,
235082
235093
  EditorView.updateListener.of((update) => {
235083
235094
  if (update.view.contentDOM.firstChild && !update.view._initialTobeContentLoaded) {
235084
235095
  update.view._initialTobeContentLoaded = true;
@@ -235144,8 +235155,8 @@ class IdeDiff extends HTMLElement {
235144
235155
 
235145
235156
  const asisLineBuilder = new RangeSetBuilder();
235146
235157
  const tobeLineBuilder = new RangeSetBuilder();
235147
- const asisButtonBuilder = new RangeSetBuilder(); // ⭐️ 새로운 빌더
235148
- const tobeButtonBuilder = new RangeSetBuilder(); // ⭐️ 새로운 빌더
235158
+ const asisButtonBuilder = new RangeSetBuilder();
235159
+ const tobeButtonBuilder = new RangeSetBuilder();
235149
235160
 
235150
235161
  let asisCursor = 0;
235151
235162
  let tobeCursor = 0;
@@ -235162,7 +235173,7 @@ class IdeDiff extends HTMLElement {
235162
235173
  const tobeRangeStart = tobeCursor;
235163
235174
 
235164
235175
  switch (op) {
235165
- case diffMatchPatchExports.diff_match_patch.DIFF_INSERT: // TOBE에 추가된 내용 (ASIS에는 없음)
235176
+ case diffMatchPatchExports.diff_match_patch.DIFF_INSERT: // TOBE (AI 추천)에 추가된 내용 (ASIS에는 없음)
235166
235177
  console.log("DIFF_INSERT (TOBE added):", JSON.stringify(text));
235167
235178
  const tobeLines = text.split('\n');
235168
235179
  for (let i = 0; i < tobeLines.length; i++) {
@@ -235172,27 +235183,24 @@ class IdeDiff extends HTMLElement {
235172
235183
  tobeCursor += tobeLines[i].length + (i < tobeLines.length - 1 ? 1 : 0);
235173
235184
  }
235174
235185
 
235175
- // ⭐️ TOBE 에디터에 버튼 추가: TOBE의 추가 내용을 ASIS '되돌리기' (ASIS에서 제거)
235176
- // TOBE의 해당 Diff가 끝나는 지점에 버튼을 붙이는 것이 자연스럽습니다.
235177
- // tobeRangeStart는 Diff 청크의 시작 오프셋입니다.
235178
- // 버튼을 Line Decoration과 같은 위치에 추가하되, 별도의 builder 사용
235186
+ // ⭐️ TOBE (AI 추천) 에디터에 버튼 추가: TOBE의 추가 내용을 ASIS (현재 소스)에 '적용'
235179
235187
  tobeButtonBuilder.add(
235180
- tobeRangeStart, // TOBE에서의 해당 Diff 청크 시작 오프셋
235188
+ tobeRangeStart,
235181
235189
  tobeRangeStart,
235182
235190
  Decoration.widget({
235183
235191
  widget: new MergeButtonWidget(
235184
- false, // 이 버튼은 TOBE 에디터에 붙는 버튼 (되돌리기)
235185
- "", // ASIS에서 해당 내용을 제거하므로 삽입할 텍스트는 없음 (즉, 삭제)
235186
- currentInstance.#asisEditorView, // 대상 에디터는 ASIS
235187
- { from: asisRangeStart, to: asisRangeStart + text.length }, // ASIS에서 '삭제될' 범위
235192
+ false, // 이 버튼은 TOBE 에디터에 붙는 버튼
235193
+ text, // AI가 추가한 내용을 ASIS에 '삽입'
235194
+ currentInstance.#asisEditorView, // 대상 에디터는 ASIS (현재 소스)
235195
+ { from: asisRangeStart, to: asisRangeStart + 0 }, // ASIS에서의 '삽입될' 위치
235188
235196
  currentInstance
235189
235197
  ),
235190
- side: 1 // 텍스트 뒤에 삽입 (이전에 `side: -1`로 시도했다면 `-1`이 우선순위가 더 높습니다.)
235198
+ side: 1
235191
235199
  })
235192
235200
  );
235193
235201
  break;
235194
235202
 
235195
- case diffMatchPatchExports.diff_match_patch.DIFF_DELETE: // ASIS에서 삭제된 내용 (TOBE에는 없음)
235203
+ case diffMatchPatchExports.diff_match_patch.DIFF_DELETE: // ASIS (현재 소스)에서 삭제된 내용 (TOBE에는 없음)
235196
235204
  console.log("DIFF_DELETE (ASIS deleted):", JSON.stringify(text));
235197
235205
  const asisLines = text.split('\n');
235198
235206
  for (let i = 0; i < asisLines.length; i++) {
@@ -235202,19 +235210,19 @@ class IdeDiff extends HTMLElement {
235202
235210
  asisCursor += asisLines[i].length + (i < asisLines.length - 1 ? 1 : 0);
235203
235211
  }
235204
235212
 
235205
- // ⭐️ ASIS 에디터에 버튼 추가: ASIS의 삭제 내용을 TOBE로 '적용' (TOBE 해당 내용 삽입)
235213
+ // ⭐️ ASIS (현재 소스) 에디터에 버튼 추가: AI가 삭제한 것을 ASIS 기준으로 '되돌리기' (TOBE에서 해당 내용을 제거)
235206
235214
  asisButtonBuilder.add(
235207
- asisRangeStart, // ASIS에서의 해당 Diff 청크 시작 오프셋
235215
+ asisRangeStart,
235208
235216
  asisRangeStart,
235209
235217
  Decoration.widget({
235210
235218
  widget: new MergeButtonWidget(
235211
- true, // 이 버튼은 ASIS 에디터에 붙는 버튼 (적용)
235212
- text, // ASIS에서 삭제된 내용을 TOBE에 삽입
235213
- currentInstance.#tobeEditorView, // 대상 에디터는 TOBE
235214
- { from: tobeRangeStart, to: tobeRangeStart + 0 }, // TOBE에서 '삽입될' 위치
235219
+ true, // 이 버튼은 ASIS 에디터에 붙는 버튼
235220
+ "", // TOBE에서 해당 내용을 '제거'하므로 삽입할 텍스트는 없음
235221
+ currentInstance.#tobeEditorView, // 대상 에디터는 TOBE (AI 추천)
235222
+ { from: tobeRangeStart, to: tobeRangeStart + text.length }, // TOBE에서 '삭제될' 범위
235215
235223
  currentInstance
235216
235224
  ),
235217
- side: 1 // 텍스트 뒤에 삽입
235225
+ side: 1
235218
235226
  })
235219
235227
  );
235220
235228
  break;
@@ -235229,8 +235237,8 @@ class IdeDiff extends HTMLElement {
235229
235237
  return {
235230
235238
  asisDecorations: asisLineBuilder.finish(),
235231
235239
  tobeDecorations: tobeLineBuilder.finish(),
235232
- asisButtonDecorations: asisButtonBuilder.finish(), // ⭐️ 추가 반환
235233
- tobeButtonDecorations: tobeButtonBuilder.finish() // ⭐️ 추가 반환
235240
+ asisButtonDecorations: asisButtonBuilder.finish(),
235241
+ tobeButtonDecorations: tobeButtonBuilder.finish()
235234
235242
  };
235235
235243
  };
235236
235244
 
@@ -235243,13 +235251,13 @@ class IdeDiff extends HTMLElement {
235243
235251
  this.#asisEditorView.dispatch({
235244
235252
  effects: [
235245
235253
  setAsisDecorationsEffect.of(asisDecorations),
235246
- setAsisButtonDecorationsEffect.of(asisButtonDecorations) // ⭐️ Effect 추가
235254
+ setAsisButtonDecorationsEffect.of(asisButtonDecorations)
235247
235255
  ]
235248
235256
  });
235249
235257
  this.#tobeEditorView.dispatch({
235250
235258
  effects: [
235251
235259
  setTobeDecorationsEffect.of(tobeDecorations),
235252
- setTobeButtonDecorationsEffect.of(tobeButtonDecorations) // ⭐️ Effect 추가
235260
+ setTobeButtonDecorationsEffect.of(tobeButtonDecorations)
235253
235261
  ]
235254
235262
  });
235255
235263
  };
@@ -234899,22 +234899,34 @@ const tobeButtonDecorations = StateField.define({
234899
234899
  class MergeButtonWidget extends WidgetType {
234900
234900
  constructor(isAsisButton, textToApply, targetEditorView, diffRange, hostComponent) {
234901
234901
  super();
234902
- this.isAsisButton = isAsisButton;
234903
- this.textToApply = textToApply;
234904
- this.targetEditorView = targetEditorView;
234905
- this.diffRange = diffRange;
234906
- this.hostComponent = hostComponent;
234902
+ this.isAsisButton = isAsisButton; // 이 버튼이 ASIS 에디터에 붙는 버튼인가 (true) TOBE 에디터에 붙는 버튼인가 (false)
234903
+ this.textToApply = textToApply; // 적용할 텍스트
234904
+ this.targetEditorView = targetEditorView; // 텍스트를 적용할 에디터 뷰 (상대편 에디터)
234905
+ this.diffRange = diffRange; // 대상 에디터에서 변경이 일어날 정확한 from/to 오프셋
234906
+ this.hostComponent = hostComponent; // IdeDiff 인스턴스 참조
234907
234907
  }
234908
234908
 
234909
+ // 위젯이 차지할 공간을 텍스트 줄에 할당할지 여부. false로 설정하여 버튼이 줄 사이에 끼어들지 않도록 함.
234909
234910
  eq(other) { return false; }
234910
234911
 
234912
+ // 위젯의 DOM 요소를 생성합니다.
234911
234913
  toDOM(view) {
234912
234914
  const button = document.createElement("button");
234913
- button.className = `cm-merge-button ${this.isAsisButton ? 'accept' : 'revert'}`;
234914
- button.textContent = this.isAsisButton ? "→ 적용" : "← 되돌리기";
234915
+ // SVN 기준 명칭으로 변경
234916
+ if (this.isAsisButton) {
234917
+ // ASIS (왼쪽) 에디터에 붙는 버튼: AI가 삭제한 것을 '되돌리기'
234918
+ button.className = "cm-merge-button revert"; // 'revert' 클래스 사용
234919
+ button.textContent = "← 되돌리기";
234920
+ } else {
234921
+ // TOBE (오른쪽) 에디터에 붙는 버튼: AI가 추가한 것을 '적용'
234922
+ button.className = "cm-merge-button accept"; // 'accept' 클래스 사용
234923
+ button.textContent = "→ 적용";
234924
+ }
234925
+
234915
234926
 
234927
+ // 클릭 이벤트 핸들러
234916
234928
  button.addEventListener("click", () => {
234917
- console.log(`버튼 클릭: ${this.isAsisButton ? 'ASIS -> TOBE' : 'TOBE -> ASIS'}`, this.textToApply);
234929
+ console.log(`버튼 클릭: ${this.isAsisButton ? 'ASIS (되돌리기)' : 'TOBE (적용)'}`, this.textToApply);
234918
234930
  console.log("대상 에디터:", this.targetEditorView === this.hostComponent.asisEditorView ? "ASIS" : "TOBE");
234919
234931
  console.log("대상 범위:", this.diffRange);
234920
234932
 
@@ -234927,22 +234939,13 @@ class MergeButtonWidget extends WidgetType {
234927
234939
  return container;
234928
234940
  }
234929
234941
 
234942
+ // 실제 변경 적용 로직
234930
234943
  applyChanges(text, editorView, range) {
234931
234944
  if (!editorView || !range) {
234932
234945
  console.error("Target editor view or range is undefined.", editorView, range);
234933
234946
  return;
234934
234947
  }
234935
234948
 
234936
- // 특정 줄의 시작 오프셋과 끝 오프셋을 정확히 계산하여 적용해야 합니다.
234937
- // 현재 로직은 단순 치환이므로 Diff 유형에 따라 복잡해질 수 있습니다.
234938
- // 예를 들어, TOBE에 삽입된 내용을 ASIS에서 되돌릴 경우, ASIS에서 해당 내용 길이만큼의 공백을 지워야 합니다.
234939
- // ASIS에서 삭제된 내용을 TOBE에 적용할 경우, TOBE의 해당 위치에 내용을 삽입해야 합니다.
234940
-
234941
- // CodeMirror의 Doc에서 특정 범위를 가져오는 것은 `state.sliceDoc(from, to)`
234942
- // `dmp.diff_main`의 결과는 줄 단위로 매핑된 문자열이므로,
234943
- // 실제 오프셋 계산 및 적용 로직은 더 정교해야 합니다.
234944
- // 지금은 임시로 range.from, range.to를 사용합니다.
234945
-
234946
234949
  editorView.dispatch({
234947
234950
  changes: {
234948
234951
  from: range.from,
@@ -234970,9 +234973,14 @@ class IdeDiff extends HTMLElement {
234970
234973
  _asisScrollHandler = null;
234971
234974
  _tobeScrollHandler = null;
234972
234975
 
234976
+ // MergeButtonWidget에서 접근할 수 있도록 Getter를 공개합니다.
234973
234977
  get asisEditorView() {
234974
234978
  return this.#asisEditorView;
234975
- };
234979
+ }
234980
+ get tobeEditorView() {
234981
+ return this.#tobeEditorView;
234982
+ }
234983
+
234976
234984
 
234977
234985
  constructor() {
234978
234986
  super();
@@ -234982,7 +234990,9 @@ class IdeDiff extends HTMLElement {
234982
234990
  connectedCallback() {
234983
234991
  this.shadowRoot.innerHTML = `
234984
234992
  <style>
234993
+ /* ninegrid CSS 및 필요한 기본 스타일 임포트 */
234985
234994
  @import "https://cdn.jsdelivr.net/npm/ninegrid@${ninegrid.version}/dist/css/ideDiff.css";
234995
+ /* 새로 만든 ideDiff.css 파일 임포트 */
234986
234996
  ${ninegrid.getCustomPath(this, "ideDiff.css")}
234987
234997
  </style>
234988
234998
 
@@ -235053,9 +235063,9 @@ class IdeDiff extends HTMLElement {
235053
235063
  extensions: [
235054
235064
  basicExtensions,
235055
235065
  this.#languageCompartment.of(javascript()),
235056
- EditorState.readOnly.of(true),
235066
+ EditorState.readOnly.of(true), // ASIS는 읽기 전용 유지 (원본 소스)
235057
235067
  asisDiffDecorations,
235058
- asisButtonDecorations, // ⭐️ 새로운 StateField 추가
235068
+ asisButtonDecorations,
235059
235069
  EditorView.updateListener.of((update) => {
235060
235070
  if (update.view.contentDOM.firstChild && !update.view._initialAsisContentLoaded) {
235061
235071
  update.view._initialAsisContentLoaded = true;
@@ -235073,8 +235083,9 @@ class IdeDiff extends HTMLElement {
235073
235083
  extensions: [
235074
235084
  basicExtensions,
235075
235085
  this.#languageCompartment.of(javascript()),
235086
+ // EditorState.readOnly.of(true), // TOBE는 AI 추천 소스이므로 편집 가능 (혹은 ASIS로만 적용)
235076
235087
  tobeDiffDecorations,
235077
- tobeButtonDecorations, // ⭐️ 새로운 StateField 추가
235088
+ tobeButtonDecorations,
235078
235089
  EditorView.updateListener.of((update) => {
235079
235090
  if (update.view.contentDOM.firstChild && !update.view._initialTobeContentLoaded) {
235080
235091
  update.view._initialTobeContentLoaded = true;
@@ -235140,8 +235151,8 @@ class IdeDiff extends HTMLElement {
235140
235151
 
235141
235152
  const asisLineBuilder = new RangeSetBuilder();
235142
235153
  const tobeLineBuilder = new RangeSetBuilder();
235143
- const asisButtonBuilder = new RangeSetBuilder(); // ⭐️ 새로운 빌더
235144
- const tobeButtonBuilder = new RangeSetBuilder(); // ⭐️ 새로운 빌더
235154
+ const asisButtonBuilder = new RangeSetBuilder();
235155
+ const tobeButtonBuilder = new RangeSetBuilder();
235145
235156
 
235146
235157
  let asisCursor = 0;
235147
235158
  let tobeCursor = 0;
@@ -235158,7 +235169,7 @@ class IdeDiff extends HTMLElement {
235158
235169
  const tobeRangeStart = tobeCursor;
235159
235170
 
235160
235171
  switch (op) {
235161
- case diffMatchPatchExports.diff_match_patch.DIFF_INSERT: // TOBE에 추가된 내용 (ASIS에는 없음)
235172
+ case diffMatchPatchExports.diff_match_patch.DIFF_INSERT: // TOBE (AI 추천)에 추가된 내용 (ASIS에는 없음)
235162
235173
  console.log("DIFF_INSERT (TOBE added):", JSON.stringify(text));
235163
235174
  const tobeLines = text.split('\n');
235164
235175
  for (let i = 0; i < tobeLines.length; i++) {
@@ -235168,27 +235179,24 @@ class IdeDiff extends HTMLElement {
235168
235179
  tobeCursor += tobeLines[i].length + (i < tobeLines.length - 1 ? 1 : 0);
235169
235180
  }
235170
235181
 
235171
- // ⭐️ TOBE 에디터에 버튼 추가: TOBE의 추가 내용을 ASIS '되돌리기' (ASIS에서 제거)
235172
- // TOBE의 해당 Diff가 끝나는 지점에 버튼을 붙이는 것이 자연스럽습니다.
235173
- // tobeRangeStart는 Diff 청크의 시작 오프셋입니다.
235174
- // 버튼을 Line Decoration과 같은 위치에 추가하되, 별도의 builder 사용
235182
+ // ⭐️ TOBE (AI 추천) 에디터에 버튼 추가: TOBE의 추가 내용을 ASIS (현재 소스)에 '적용'
235175
235183
  tobeButtonBuilder.add(
235176
- tobeRangeStart, // TOBE에서의 해당 Diff 청크 시작 오프셋
235184
+ tobeRangeStart,
235177
235185
  tobeRangeStart,
235178
235186
  Decoration.widget({
235179
235187
  widget: new MergeButtonWidget(
235180
- false, // 이 버튼은 TOBE 에디터에 붙는 버튼 (되돌리기)
235181
- "", // ASIS에서 해당 내용을 제거하므로 삽입할 텍스트는 없음 (즉, 삭제)
235182
- currentInstance.#asisEditorView, // 대상 에디터는 ASIS
235183
- { from: asisRangeStart, to: asisRangeStart + text.length }, // ASIS에서 '삭제될' 범위
235188
+ false, // 이 버튼은 TOBE 에디터에 붙는 버튼
235189
+ text, // AI가 추가한 내용을 ASIS에 '삽입'
235190
+ currentInstance.#asisEditorView, // 대상 에디터는 ASIS (현재 소스)
235191
+ { from: asisRangeStart, to: asisRangeStart + 0 }, // ASIS에서의 '삽입될' 위치
235184
235192
  currentInstance
235185
235193
  ),
235186
- side: 1 // 텍스트 뒤에 삽입 (이전에 `side: -1`로 시도했다면 `-1`이 우선순위가 더 높습니다.)
235194
+ side: 1
235187
235195
  })
235188
235196
  );
235189
235197
  break;
235190
235198
 
235191
- case diffMatchPatchExports.diff_match_patch.DIFF_DELETE: // ASIS에서 삭제된 내용 (TOBE에는 없음)
235199
+ case diffMatchPatchExports.diff_match_patch.DIFF_DELETE: // ASIS (현재 소스)에서 삭제된 내용 (TOBE에는 없음)
235192
235200
  console.log("DIFF_DELETE (ASIS deleted):", JSON.stringify(text));
235193
235201
  const asisLines = text.split('\n');
235194
235202
  for (let i = 0; i < asisLines.length; i++) {
@@ -235198,19 +235206,19 @@ class IdeDiff extends HTMLElement {
235198
235206
  asisCursor += asisLines[i].length + (i < asisLines.length - 1 ? 1 : 0);
235199
235207
  }
235200
235208
 
235201
- // ⭐️ ASIS 에디터에 버튼 추가: ASIS의 삭제 내용을 TOBE로 '적용' (TOBE 해당 내용 삽입)
235209
+ // ⭐️ ASIS (현재 소스) 에디터에 버튼 추가: AI가 삭제한 것을 ASIS 기준으로 '되돌리기' (TOBE에서 해당 내용을 제거)
235202
235210
  asisButtonBuilder.add(
235203
- asisRangeStart, // ASIS에서의 해당 Diff 청크 시작 오프셋
235211
+ asisRangeStart,
235204
235212
  asisRangeStart,
235205
235213
  Decoration.widget({
235206
235214
  widget: new MergeButtonWidget(
235207
- true, // 이 버튼은 ASIS 에디터에 붙는 버튼 (적용)
235208
- text, // ASIS에서 삭제된 내용을 TOBE에 삽입
235209
- currentInstance.#tobeEditorView, // 대상 에디터는 TOBE
235210
- { from: tobeRangeStart, to: tobeRangeStart + 0 }, // TOBE에서 '삽입될' 위치
235215
+ true, // 이 버튼은 ASIS 에디터에 붙는 버튼
235216
+ "", // TOBE에서 해당 내용을 '제거'하므로 삽입할 텍스트는 없음
235217
+ currentInstance.#tobeEditorView, // 대상 에디터는 TOBE (AI 추천)
235218
+ { from: tobeRangeStart, to: tobeRangeStart + text.length }, // TOBE에서 '삭제될' 범위
235211
235219
  currentInstance
235212
235220
  ),
235213
- side: 1 // 텍스트 뒤에 삽입
235221
+ side: 1
235214
235222
  })
235215
235223
  );
235216
235224
  break;
@@ -235225,8 +235233,8 @@ class IdeDiff extends HTMLElement {
235225
235233
  return {
235226
235234
  asisDecorations: asisLineBuilder.finish(),
235227
235235
  tobeDecorations: tobeLineBuilder.finish(),
235228
- asisButtonDecorations: asisButtonBuilder.finish(), // ⭐️ 추가 반환
235229
- tobeButtonDecorations: tobeButtonBuilder.finish() // ⭐️ 추가 반환
235236
+ asisButtonDecorations: asisButtonBuilder.finish(),
235237
+ tobeButtonDecorations: tobeButtonBuilder.finish()
235230
235238
  };
235231
235239
  };
235232
235240
 
@@ -235239,13 +235247,13 @@ class IdeDiff extends HTMLElement {
235239
235247
  this.#asisEditorView.dispatch({
235240
235248
  effects: [
235241
235249
  setAsisDecorationsEffect.of(asisDecorations),
235242
- setAsisButtonDecorationsEffect.of(asisButtonDecorations) // ⭐️ Effect 추가
235250
+ setAsisButtonDecorationsEffect.of(asisButtonDecorations)
235243
235251
  ]
235244
235252
  });
235245
235253
  this.#tobeEditorView.dispatch({
235246
235254
  effects: [
235247
235255
  setTobeDecorationsEffect.of(tobeDecorations),
235248
- setTobeButtonDecorationsEffect.of(tobeButtonDecorations) // ⭐️ Effect 추가
235256
+ setTobeButtonDecorationsEffect.of(tobeButtonDecorations)
235249
235257
  ]
235250
235258
  });
235251
235259
  };
@@ -99,22 +99,34 @@ const tobeButtonDecorations = StateField.define({
99
99
  class MergeButtonWidget extends WidgetType {
100
100
  constructor(isAsisButton, textToApply, targetEditorView, diffRange, hostComponent) {
101
101
  super();
102
- this.isAsisButton = isAsisButton;
103
- this.textToApply = textToApply;
104
- this.targetEditorView = targetEditorView;
105
- this.diffRange = diffRange;
106
- this.hostComponent = hostComponent;
102
+ this.isAsisButton = isAsisButton; // 이 버튼이 ASIS 에디터에 붙는 버튼인가 (true) TOBE 에디터에 붙는 버튼인가 (false)
103
+ this.textToApply = textToApply; // 적용할 텍스트
104
+ this.targetEditorView = targetEditorView; // 텍스트를 적용할 에디터 뷰 (상대편 에디터)
105
+ this.diffRange = diffRange; // 대상 에디터에서 변경이 일어날 정확한 from/to 오프셋
106
+ this.hostComponent = hostComponent; // IdeDiff 인스턴스 참조
107
107
  }
108
108
 
109
+ // 위젯이 차지할 공간을 텍스트 줄에 할당할지 여부. false로 설정하여 버튼이 줄 사이에 끼어들지 않도록 함.
109
110
  eq(other) { return false; }
110
111
 
112
+ // 위젯의 DOM 요소를 생성합니다.
111
113
  toDOM(view) {
112
114
  const button = document.createElement("button");
113
- button.className = `cm-merge-button ${this.isAsisButton ? 'accept' : 'revert'}`;
114
- button.textContent = this.isAsisButton ? "→ 적용" : "← 되돌리기";
115
+ // SVN 기준 명칭으로 변경
116
+ if (this.isAsisButton) {
117
+ // ASIS (왼쪽) 에디터에 붙는 버튼: AI가 삭제한 것을 '되돌리기'
118
+ button.className = "cm-merge-button revert"; // 'revert' 클래스 사용
119
+ button.textContent = "← 되돌리기";
120
+ } else {
121
+ // TOBE (오른쪽) 에디터에 붙는 버튼: AI가 추가한 것을 '적용'
122
+ button.className = "cm-merge-button accept"; // 'accept' 클래스 사용
123
+ button.textContent = "→ 적용";
124
+ }
125
+
115
126
 
127
+ // 클릭 이벤트 핸들러
116
128
  button.addEventListener("click", () => {
117
- console.log(`버튼 클릭: ${this.isAsisButton ? 'ASIS -> TOBE' : 'TOBE -> ASIS'}`, this.textToApply);
129
+ console.log(`버튼 클릭: ${this.isAsisButton ? 'ASIS (되돌리기)' : 'TOBE (적용)'}`, this.textToApply);
118
130
  console.log("대상 에디터:", this.targetEditorView === this.hostComponent.asisEditorView ? "ASIS" : "TOBE");
119
131
  console.log("대상 범위:", this.diffRange);
120
132
 
@@ -127,22 +139,13 @@ class MergeButtonWidget extends WidgetType {
127
139
  return container;
128
140
  }
129
141
 
142
+ // 실제 변경 적용 로직
130
143
  applyChanges(text, editorView, range) {
131
144
  if (!editorView || !range) {
132
145
  console.error("Target editor view or range is undefined.", editorView, range);
133
146
  return;
134
147
  }
135
148
 
136
- // 특정 줄의 시작 오프셋과 끝 오프셋을 정확히 계산하여 적용해야 합니다.
137
- // 현재 로직은 단순 치환이므로 Diff 유형에 따라 복잡해질 수 있습니다.
138
- // 예를 들어, TOBE에 삽입된 내용을 ASIS에서 되돌릴 경우, ASIS에서 해당 내용 길이만큼의 공백을 지워야 합니다.
139
- // ASIS에서 삭제된 내용을 TOBE에 적용할 경우, TOBE의 해당 위치에 내용을 삽입해야 합니다.
140
-
141
- // CodeMirror의 Doc에서 특정 범위를 가져오는 것은 `state.sliceDoc(from, to)`
142
- // `dmp.diff_main`의 결과는 줄 단위로 매핑된 문자열이므로,
143
- // 실제 오프셋 계산 및 적용 로직은 더 정교해야 합니다.
144
- // 지금은 임시로 range.from, range.to를 사용합니다.
145
-
146
149
  editorView.dispatch({
147
150
  changes: {
148
151
  from: range.from,
@@ -170,9 +173,14 @@ export class IdeDiff extends HTMLElement {
170
173
  _asisScrollHandler = null;
171
174
  _tobeScrollHandler = null;
172
175
 
176
+ // MergeButtonWidget에서 접근할 수 있도록 Getter를 공개합니다.
173
177
  get asisEditorView() {
174
178
  return this.#asisEditorView;
175
- };
179
+ }
180
+ get tobeEditorView() {
181
+ return this.#tobeEditorView;
182
+ }
183
+
176
184
 
177
185
  constructor() {
178
186
  super();
@@ -182,7 +190,9 @@ export class IdeDiff extends HTMLElement {
182
190
  connectedCallback() {
183
191
  this.shadowRoot.innerHTML = `
184
192
  <style>
193
+ /* ninegrid CSS 및 필요한 기본 스타일 임포트 */
185
194
  @import "https://cdn.jsdelivr.net/npm/ninegrid@${ninegrid.version}/dist/css/ideDiff.css";
195
+ /* 새로 만든 ideDiff.css 파일 임포트 */
186
196
  ${ninegrid.getCustomPath(this, "ideDiff.css")}
187
197
  </style>
188
198
 
@@ -253,9 +263,9 @@ export class IdeDiff extends HTMLElement {
253
263
  extensions: [
254
264
  basicExtensions,
255
265
  this.#languageCompartment.of(javascript()),
256
- EditorState.readOnly.of(true),
266
+ EditorState.readOnly.of(true), // ASIS는 읽기 전용 유지 (원본 소스)
257
267
  asisDiffDecorations,
258
- asisButtonDecorations, // ⭐️ 새로운 StateField 추가
268
+ asisButtonDecorations,
259
269
  EditorView.updateListener.of((update) => {
260
270
  if (update.view.contentDOM.firstChild && !update.view._initialAsisContentLoaded) {
261
271
  update.view._initialAsisContentLoaded = true;
@@ -273,8 +283,9 @@ export class IdeDiff extends HTMLElement {
273
283
  extensions: [
274
284
  basicExtensions,
275
285
  this.#languageCompartment.of(javascript()),
286
+ // EditorState.readOnly.of(true), // TOBE는 AI 추천 소스이므로 편집 가능 (혹은 ASIS로만 적용)
276
287
  tobeDiffDecorations,
277
- tobeButtonDecorations, // ⭐️ 새로운 StateField 추가
288
+ tobeButtonDecorations,
278
289
  EditorView.updateListener.of((update) => {
279
290
  if (update.view.contentDOM.firstChild && !update.view._initialTobeContentLoaded) {
280
291
  update.view._initialTobeContentLoaded = true;
@@ -340,8 +351,8 @@ export class IdeDiff extends HTMLElement {
340
351
 
341
352
  const asisLineBuilder = new RangeSetBuilder();
342
353
  const tobeLineBuilder = new RangeSetBuilder();
343
- const asisButtonBuilder = new RangeSetBuilder(); // ⭐️ 새로운 빌더
344
- const tobeButtonBuilder = new RangeSetBuilder(); // ⭐️ 새로운 빌더
354
+ const asisButtonBuilder = new RangeSetBuilder();
355
+ const tobeButtonBuilder = new RangeSetBuilder();
345
356
 
346
357
  let asisCursor = 0;
347
358
  let tobeCursor = 0;
@@ -358,7 +369,7 @@ export class IdeDiff extends HTMLElement {
358
369
  const tobeRangeStart = tobeCursor;
359
370
 
360
371
  switch (op) {
361
- case diff_match_patch.DIFF_INSERT: // TOBE에 추가된 내용 (ASIS에는 없음)
372
+ case diff_match_patch.DIFF_INSERT: // TOBE (AI 추천)에 추가된 내용 (ASIS에는 없음)
362
373
  console.log("DIFF_INSERT (TOBE added):", JSON.stringify(text));
363
374
  const tobeLines = text.split('\n');
364
375
  for (let i = 0; i < tobeLines.length; i++) {
@@ -368,27 +379,24 @@ export class IdeDiff extends HTMLElement {
368
379
  tobeCursor += tobeLines[i].length + (i < tobeLines.length - 1 ? 1 : 0);
369
380
  }
370
381
 
371
- // ⭐️ TOBE 에디터에 버튼 추가: TOBE의 추가 내용을 ASIS '되돌리기' (ASIS에서 제거)
372
- // TOBE의 해당 Diff가 끝나는 지점에 버튼을 붙이는 것이 자연스럽습니다.
373
- // tobeRangeStart는 Diff 청크의 시작 오프셋입니다.
374
- // 버튼을 Line Decoration과 같은 위치에 추가하되, 별도의 builder 사용
382
+ // ⭐️ TOBE (AI 추천) 에디터에 버튼 추가: TOBE의 추가 내용을 ASIS (현재 소스)에 '적용'
375
383
  tobeButtonBuilder.add(
376
- tobeRangeStart, // TOBE에서의 해당 Diff 청크 시작 오프셋
384
+ tobeRangeStart,
377
385
  tobeRangeStart,
378
386
  Decoration.widget({
379
387
  widget: new MergeButtonWidget(
380
- false, // 이 버튼은 TOBE 에디터에 붙는 버튼 (되돌리기)
381
- "", // ASIS에서 해당 내용을 제거하므로 삽입할 텍스트는 없음 (즉, 삭제)
382
- currentInstance.#asisEditorView, // 대상 에디터는 ASIS
383
- { from: asisRangeStart, to: asisRangeStart + text.length }, // ASIS에서 '삭제될' 범위
388
+ false, // 이 버튼은 TOBE 에디터에 붙는 버튼
389
+ text, // AI가 추가한 내용을 ASIS에 '삽입'
390
+ currentInstance.#asisEditorView, // 대상 에디터는 ASIS (현재 소스)
391
+ { from: asisRangeStart, to: asisRangeStart + 0 }, // ASIS에서의 '삽입될' 위치
384
392
  currentInstance
385
393
  ),
386
- side: 1 // 텍스트 뒤에 삽입 (이전에 `side: -1`로 시도했다면 `-1`이 우선순위가 더 높습니다.)
394
+ side: 1
387
395
  })
388
396
  );
389
397
  break;
390
398
 
391
- case diff_match_patch.DIFF_DELETE: // ASIS에서 삭제된 내용 (TOBE에는 없음)
399
+ case diff_match_patch.DIFF_DELETE: // ASIS (현재 소스)에서 삭제된 내용 (TOBE에는 없음)
392
400
  console.log("DIFF_DELETE (ASIS deleted):", JSON.stringify(text));
393
401
  const asisLines = text.split('\n');
394
402
  for (let i = 0; i < asisLines.length; i++) {
@@ -398,19 +406,19 @@ export class IdeDiff extends HTMLElement {
398
406
  asisCursor += asisLines[i].length + (i < asisLines.length - 1 ? 1 : 0);
399
407
  }
400
408
 
401
- // ⭐️ ASIS 에디터에 버튼 추가: ASIS의 삭제 내용을 TOBE로 '적용' (TOBE 해당 내용 삽입)
409
+ // ⭐️ ASIS (현재 소스) 에디터에 버튼 추가: AI가 삭제한 것을 ASIS 기준으로 '되돌리기' (TOBE에서 해당 내용을 제거)
402
410
  asisButtonBuilder.add(
403
- asisRangeStart, // ASIS에서의 해당 Diff 청크 시작 오프셋
411
+ asisRangeStart,
404
412
  asisRangeStart,
405
413
  Decoration.widget({
406
414
  widget: new MergeButtonWidget(
407
- true, // 이 버튼은 ASIS 에디터에 붙는 버튼 (적용)
408
- text, // ASIS에서 삭제된 내용을 TOBE에 삽입
409
- currentInstance.#tobeEditorView, // 대상 에디터는 TOBE
410
- { from: tobeRangeStart, to: tobeRangeStart + 0 }, // TOBE에서 '삽입될' 위치
415
+ true, // 이 버튼은 ASIS 에디터에 붙는 버튼
416
+ "", // TOBE에서 해당 내용을 '제거'하므로 삽입할 텍스트는 없음
417
+ currentInstance.#tobeEditorView, // 대상 에디터는 TOBE (AI 추천)
418
+ { from: tobeRangeStart, to: tobeRangeStart + text.length }, // TOBE에서 '삭제될' 범위
411
419
  currentInstance
412
420
  ),
413
- side: 1 // 텍스트 뒤에 삽입
421
+ side: 1
414
422
  })
415
423
  );
416
424
  break;
@@ -425,8 +433,8 @@ export class IdeDiff extends HTMLElement {
425
433
  return {
426
434
  asisDecorations: asisLineBuilder.finish(),
427
435
  tobeDecorations: tobeLineBuilder.finish(),
428
- asisButtonDecorations: asisButtonBuilder.finish(), // ⭐️ 추가 반환
429
- tobeButtonDecorations: tobeButtonBuilder.finish() // ⭐️ 추가 반환
436
+ asisButtonDecorations: asisButtonBuilder.finish(),
437
+ tobeButtonDecorations: tobeButtonBuilder.finish()
430
438
  };
431
439
  };
432
440
 
@@ -439,13 +447,13 @@ export class IdeDiff extends HTMLElement {
439
447
  this.#asisEditorView.dispatch({
440
448
  effects: [
441
449
  setAsisDecorationsEffect.of(asisDecorations),
442
- setAsisButtonDecorationsEffect.of(asisButtonDecorations) // ⭐️ Effect 추가
450
+ setAsisButtonDecorationsEffect.of(asisButtonDecorations)
443
451
  ]
444
452
  });
445
453
  this.#tobeEditorView.dispatch({
446
454
  effects: [
447
455
  setTobeDecorationsEffect.of(tobeDecorations),
448
- setTobeButtonDecorationsEffect.of(tobeButtonDecorations) // ⭐️ Effect 추가
456
+ setTobeButtonDecorationsEffect.of(tobeButtonDecorations)
449
457
  ]
450
458
  });
451
459
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ide-assi",
3
3
  "type": "module",
4
- "version": "0.441.0",
4
+ "version": "0.442.0",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "exports": {
@@ -99,22 +99,34 @@ const tobeButtonDecorations = StateField.define({
99
99
  class MergeButtonWidget extends WidgetType {
100
100
  constructor(isAsisButton, textToApply, targetEditorView, diffRange, hostComponent) {
101
101
  super();
102
- this.isAsisButton = isAsisButton;
103
- this.textToApply = textToApply;
104
- this.targetEditorView = targetEditorView;
105
- this.diffRange = diffRange;
106
- this.hostComponent = hostComponent;
102
+ this.isAsisButton = isAsisButton; // 이 버튼이 ASIS 에디터에 붙는 버튼인가 (true) TOBE 에디터에 붙는 버튼인가 (false)
103
+ this.textToApply = textToApply; // 적용할 텍스트
104
+ this.targetEditorView = targetEditorView; // 텍스트를 적용할 에디터 뷰 (상대편 에디터)
105
+ this.diffRange = diffRange; // 대상 에디터에서 변경이 일어날 정확한 from/to 오프셋
106
+ this.hostComponent = hostComponent; // IdeDiff 인스턴스 참조
107
107
  }
108
108
 
109
+ // 위젯이 차지할 공간을 텍스트 줄에 할당할지 여부. false로 설정하여 버튼이 줄 사이에 끼어들지 않도록 함.
109
110
  eq(other) { return false; }
110
111
 
112
+ // 위젯의 DOM 요소를 생성합니다.
111
113
  toDOM(view) {
112
114
  const button = document.createElement("button");
113
- button.className = `cm-merge-button ${this.isAsisButton ? 'accept' : 'revert'}`;
114
- button.textContent = this.isAsisButton ? "→ 적용" : "← 되돌리기";
115
+ // SVN 기준 명칭으로 변경
116
+ if (this.isAsisButton) {
117
+ // ASIS (왼쪽) 에디터에 붙는 버튼: AI가 삭제한 것을 '되돌리기'
118
+ button.className = "cm-merge-button revert"; // 'revert' 클래스 사용
119
+ button.textContent = "← 되돌리기";
120
+ } else {
121
+ // TOBE (오른쪽) 에디터에 붙는 버튼: AI가 추가한 것을 '적용'
122
+ button.className = "cm-merge-button accept"; // 'accept' 클래스 사용
123
+ button.textContent = "→ 적용";
124
+ }
125
+
115
126
 
127
+ // 클릭 이벤트 핸들러
116
128
  button.addEventListener("click", () => {
117
- console.log(`버튼 클릭: ${this.isAsisButton ? 'ASIS -> TOBE' : 'TOBE -> ASIS'}`, this.textToApply);
129
+ console.log(`버튼 클릭: ${this.isAsisButton ? 'ASIS (되돌리기)' : 'TOBE (적용)'}`, this.textToApply);
118
130
  console.log("대상 에디터:", this.targetEditorView === this.hostComponent.asisEditorView ? "ASIS" : "TOBE");
119
131
  console.log("대상 범위:", this.diffRange);
120
132
 
@@ -127,22 +139,13 @@ class MergeButtonWidget extends WidgetType {
127
139
  return container;
128
140
  }
129
141
 
142
+ // 실제 변경 적용 로직
130
143
  applyChanges(text, editorView, range) {
131
144
  if (!editorView || !range) {
132
145
  console.error("Target editor view or range is undefined.", editorView, range);
133
146
  return;
134
147
  }
135
148
 
136
- // 특정 줄의 시작 오프셋과 끝 오프셋을 정확히 계산하여 적용해야 합니다.
137
- // 현재 로직은 단순 치환이므로 Diff 유형에 따라 복잡해질 수 있습니다.
138
- // 예를 들어, TOBE에 삽입된 내용을 ASIS에서 되돌릴 경우, ASIS에서 해당 내용 길이만큼의 공백을 지워야 합니다.
139
- // ASIS에서 삭제된 내용을 TOBE에 적용할 경우, TOBE의 해당 위치에 내용을 삽입해야 합니다.
140
-
141
- // CodeMirror의 Doc에서 특정 범위를 가져오는 것은 `state.sliceDoc(from, to)`
142
- // `dmp.diff_main`의 결과는 줄 단위로 매핑된 문자열이므로,
143
- // 실제 오프셋 계산 및 적용 로직은 더 정교해야 합니다.
144
- // 지금은 임시로 range.from, range.to를 사용합니다.
145
-
146
149
  editorView.dispatch({
147
150
  changes: {
148
151
  from: range.from,
@@ -170,9 +173,14 @@ export class IdeDiff extends HTMLElement {
170
173
  _asisScrollHandler = null;
171
174
  _tobeScrollHandler = null;
172
175
 
176
+ // MergeButtonWidget에서 접근할 수 있도록 Getter를 공개합니다.
173
177
  get asisEditorView() {
174
178
  return this.#asisEditorView;
175
- };
179
+ }
180
+ get tobeEditorView() {
181
+ return this.#tobeEditorView;
182
+ }
183
+
176
184
 
177
185
  constructor() {
178
186
  super();
@@ -182,7 +190,9 @@ export class IdeDiff extends HTMLElement {
182
190
  connectedCallback() {
183
191
  this.shadowRoot.innerHTML = `
184
192
  <style>
193
+ /* ninegrid CSS 및 필요한 기본 스타일 임포트 */
185
194
  @import "https://cdn.jsdelivr.net/npm/ninegrid@${ninegrid.version}/dist/css/ideDiff.css";
195
+ /* 새로 만든 ideDiff.css 파일 임포트 */
186
196
  ${ninegrid.getCustomPath(this, "ideDiff.css")}
187
197
  </style>
188
198
 
@@ -253,9 +263,9 @@ export class IdeDiff extends HTMLElement {
253
263
  extensions: [
254
264
  basicExtensions,
255
265
  this.#languageCompartment.of(javascript()),
256
- EditorState.readOnly.of(true),
266
+ EditorState.readOnly.of(true), // ASIS는 읽기 전용 유지 (원본 소스)
257
267
  asisDiffDecorations,
258
- asisButtonDecorations, // ⭐️ 새로운 StateField 추가
268
+ asisButtonDecorations,
259
269
  EditorView.updateListener.of((update) => {
260
270
  if (update.view.contentDOM.firstChild && !update.view._initialAsisContentLoaded) {
261
271
  update.view._initialAsisContentLoaded = true;
@@ -273,8 +283,9 @@ export class IdeDiff extends HTMLElement {
273
283
  extensions: [
274
284
  basicExtensions,
275
285
  this.#languageCompartment.of(javascript()),
286
+ // EditorState.readOnly.of(true), // TOBE는 AI 추천 소스이므로 편집 가능 (혹은 ASIS로만 적용)
276
287
  tobeDiffDecorations,
277
- tobeButtonDecorations, // ⭐️ 새로운 StateField 추가
288
+ tobeButtonDecorations,
278
289
  EditorView.updateListener.of((update) => {
279
290
  if (update.view.contentDOM.firstChild && !update.view._initialTobeContentLoaded) {
280
291
  update.view._initialTobeContentLoaded = true;
@@ -340,8 +351,8 @@ export class IdeDiff extends HTMLElement {
340
351
 
341
352
  const asisLineBuilder = new RangeSetBuilder();
342
353
  const tobeLineBuilder = new RangeSetBuilder();
343
- const asisButtonBuilder = new RangeSetBuilder(); // ⭐️ 새로운 빌더
344
- const tobeButtonBuilder = new RangeSetBuilder(); // ⭐️ 새로운 빌더
354
+ const asisButtonBuilder = new RangeSetBuilder();
355
+ const tobeButtonBuilder = new RangeSetBuilder();
345
356
 
346
357
  let asisCursor = 0;
347
358
  let tobeCursor = 0;
@@ -358,7 +369,7 @@ export class IdeDiff extends HTMLElement {
358
369
  const tobeRangeStart = tobeCursor;
359
370
 
360
371
  switch (op) {
361
- case diff_match_patch.DIFF_INSERT: // TOBE에 추가된 내용 (ASIS에는 없음)
372
+ case diff_match_patch.DIFF_INSERT: // TOBE (AI 추천)에 추가된 내용 (ASIS에는 없음)
362
373
  console.log("DIFF_INSERT (TOBE added):", JSON.stringify(text));
363
374
  const tobeLines = text.split('\n');
364
375
  for (let i = 0; i < tobeLines.length; i++) {
@@ -368,27 +379,24 @@ export class IdeDiff extends HTMLElement {
368
379
  tobeCursor += tobeLines[i].length + (i < tobeLines.length - 1 ? 1 : 0);
369
380
  }
370
381
 
371
- // ⭐️ TOBE 에디터에 버튼 추가: TOBE의 추가 내용을 ASIS '되돌리기' (ASIS에서 제거)
372
- // TOBE의 해당 Diff가 끝나는 지점에 버튼을 붙이는 것이 자연스럽습니다.
373
- // tobeRangeStart는 Diff 청크의 시작 오프셋입니다.
374
- // 버튼을 Line Decoration과 같은 위치에 추가하되, 별도의 builder 사용
382
+ // ⭐️ TOBE (AI 추천) 에디터에 버튼 추가: TOBE의 추가 내용을 ASIS (현재 소스)에 '적용'
375
383
  tobeButtonBuilder.add(
376
- tobeRangeStart, // TOBE에서의 해당 Diff 청크 시작 오프셋
384
+ tobeRangeStart,
377
385
  tobeRangeStart,
378
386
  Decoration.widget({
379
387
  widget: new MergeButtonWidget(
380
- false, // 이 버튼은 TOBE 에디터에 붙는 버튼 (되돌리기)
381
- "", // ASIS에서 해당 내용을 제거하므로 삽입할 텍스트는 없음 (즉, 삭제)
382
- currentInstance.#asisEditorView, // 대상 에디터는 ASIS
383
- { from: asisRangeStart, to: asisRangeStart + text.length }, // ASIS에서 '삭제될' 범위
388
+ false, // 이 버튼은 TOBE 에디터에 붙는 버튼
389
+ text, // AI가 추가한 내용을 ASIS에 '삽입'
390
+ currentInstance.#asisEditorView, // 대상 에디터는 ASIS (현재 소스)
391
+ { from: asisRangeStart, to: asisRangeStart + 0 }, // ASIS에서의 '삽입될' 위치
384
392
  currentInstance
385
393
  ),
386
- side: 1 // 텍스트 뒤에 삽입 (이전에 `side: -1`로 시도했다면 `-1`이 우선순위가 더 높습니다.)
394
+ side: 1
387
395
  })
388
396
  );
389
397
  break;
390
398
 
391
- case diff_match_patch.DIFF_DELETE: // ASIS에서 삭제된 내용 (TOBE에는 없음)
399
+ case diff_match_patch.DIFF_DELETE: // ASIS (현재 소스)에서 삭제된 내용 (TOBE에는 없음)
392
400
  console.log("DIFF_DELETE (ASIS deleted):", JSON.stringify(text));
393
401
  const asisLines = text.split('\n');
394
402
  for (let i = 0; i < asisLines.length; i++) {
@@ -398,19 +406,19 @@ export class IdeDiff extends HTMLElement {
398
406
  asisCursor += asisLines[i].length + (i < asisLines.length - 1 ? 1 : 0);
399
407
  }
400
408
 
401
- // ⭐️ ASIS 에디터에 버튼 추가: ASIS의 삭제 내용을 TOBE로 '적용' (TOBE 해당 내용 삽입)
409
+ // ⭐️ ASIS (현재 소스) 에디터에 버튼 추가: AI가 삭제한 것을 ASIS 기준으로 '되돌리기' (TOBE에서 해당 내용을 제거)
402
410
  asisButtonBuilder.add(
403
- asisRangeStart, // ASIS에서의 해당 Diff 청크 시작 오프셋
411
+ asisRangeStart,
404
412
  asisRangeStart,
405
413
  Decoration.widget({
406
414
  widget: new MergeButtonWidget(
407
- true, // 이 버튼은 ASIS 에디터에 붙는 버튼 (적용)
408
- text, // ASIS에서 삭제된 내용을 TOBE에 삽입
409
- currentInstance.#tobeEditorView, // 대상 에디터는 TOBE
410
- { from: tobeRangeStart, to: tobeRangeStart + 0 }, // TOBE에서 '삽입될' 위치
415
+ true, // 이 버튼은 ASIS 에디터에 붙는 버튼
416
+ "", // TOBE에서 해당 내용을 '제거'하므로 삽입할 텍스트는 없음
417
+ currentInstance.#tobeEditorView, // 대상 에디터는 TOBE (AI 추천)
418
+ { from: tobeRangeStart, to: tobeRangeStart + text.length }, // TOBE에서 '삭제될' 범위
411
419
  currentInstance
412
420
  ),
413
- side: 1 // 텍스트 뒤에 삽입
421
+ side: 1
414
422
  })
415
423
  );
416
424
  break;
@@ -425,8 +433,8 @@ export class IdeDiff extends HTMLElement {
425
433
  return {
426
434
  asisDecorations: asisLineBuilder.finish(),
427
435
  tobeDecorations: tobeLineBuilder.finish(),
428
- asisButtonDecorations: asisButtonBuilder.finish(), // ⭐️ 추가 반환
429
- tobeButtonDecorations: tobeButtonBuilder.finish() // ⭐️ 추가 반환
436
+ asisButtonDecorations: asisButtonBuilder.finish(),
437
+ tobeButtonDecorations: tobeButtonBuilder.finish()
430
438
  };
431
439
  };
432
440
 
@@ -439,13 +447,13 @@ export class IdeDiff extends HTMLElement {
439
447
  this.#asisEditorView.dispatch({
440
448
  effects: [
441
449
  setAsisDecorationsEffect.of(asisDecorations),
442
- setAsisButtonDecorationsEffect.of(asisButtonDecorations) // ⭐️ Effect 추가
450
+ setAsisButtonDecorationsEffect.of(asisButtonDecorations)
443
451
  ]
444
452
  });
445
453
  this.#tobeEditorView.dispatch({
446
454
  effects: [
447
455
  setTobeDecorationsEffect.of(tobeDecorations),
448
- setTobeButtonDecorationsEffect.of(tobeButtonDecorations) // ⭐️ Effect 추가
456
+ setTobeButtonDecorationsEffect.of(tobeButtonDecorations)
449
457
  ]
450
458
  });
451
459
  };