ide-assi 0.441.0 → 0.443.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,33 @@ 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가 삭제한 것을 '삭제' (ASIS에서 제거)
234922
+ button.className = "cm-merge-button revert"; // 'revert' 클래스 사용 (빨간색)
234923
+ button.textContent = "삭제"; // 텍스트 변경
234924
+ } else {
234925
+ // TOBE (오른쪽) 에디터에 붙는 버튼: AI가 추가한 것을 '적용' (ASIS에 반영)
234926
+ button.className = "cm-merge-button accept"; // 'accept' 클래스 사용 (녹색)
234927
+ button.textContent = "← 적용"; // 화살표 방향 변경
234928
+ }
234919
234929
 
234930
+ // 클릭 이벤트 핸들러
234920
234931
  button.addEventListener("click", () => {
234921
- console.log(`버튼 클릭: ${this.isAsisButton ? 'ASIS -> TOBE' : 'TOBE -> ASIS'}`, this.textToApply);
234932
+ console.log(`버튼 클릭: ${this.isAsisButton ? 'ASIS (삭제)' : 'TOBE (적용)'}`, this.textToApply);
234922
234933
  console.log("대상 에디터:", this.targetEditorView === this.hostComponent.asisEditorView ? "ASIS" : "TOBE");
234923
234934
  console.log("대상 범위:", this.diffRange);
234924
234935
 
@@ -234931,22 +234942,13 @@ class MergeButtonWidget extends WidgetType {
234931
234942
  return container;
234932
234943
  }
234933
234944
 
234945
+ // 실제 변경 적용 로직
234934
234946
  applyChanges(text, editorView, range) {
234935
234947
  if (!editorView || !range) {
234936
234948
  console.error("Target editor view or range is undefined.", editorView, range);
234937
234949
  return;
234938
234950
  }
234939
234951
 
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
234952
  editorView.dispatch({
234951
234953
  changes: {
234952
234954
  from: range.from,
@@ -234974,9 +234976,14 @@ class IdeDiff extends HTMLElement {
234974
234976
  _asisScrollHandler = null;
234975
234977
  _tobeScrollHandler = null;
234976
234978
 
234979
+ // MergeButtonWidget에서 접근할 수 있도록 Getter를 공개합니다.
234977
234980
  get asisEditorView() {
234978
234981
  return this.#asisEditorView;
234979
- };
234982
+ }
234983
+ get tobeEditorView() {
234984
+ return this.#tobeEditorView;
234985
+ }
234986
+
234980
234987
 
234981
234988
  constructor() {
234982
234989
  super();
@@ -234986,7 +234993,9 @@ class IdeDiff extends HTMLElement {
234986
234993
  connectedCallback() {
234987
234994
  this.shadowRoot.innerHTML = `
234988
234995
  <style>
234996
+ /* ninegrid CSS 및 필요한 기본 스타일 임포트 */
234989
234997
  @import "https://cdn.jsdelivr.net/npm/ninegrid@${ninegrid.version}/dist/css/ideDiff.css";
234998
+ /* 새로 만든 ideDiff.css 파일 임포트 */
234990
234999
  ${ninegrid.getCustomPath(this, "ideDiff.css")}
234991
235000
  </style>
234992
235001
 
@@ -235057,9 +235066,10 @@ class IdeDiff extends HTMLElement {
235057
235066
  extensions: [
235058
235067
  basicExtensions,
235059
235068
  this.#languageCompartment.of(javascript()),
235060
- EditorState.readOnly.of(true),
235069
+ // ASIS는 읽기 전용으로 유지 (원본 소스) - 필요에 따라 편집 가능하도록 변경 가능
235070
+ EditorState.readOnly.of(false), // 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 추천 소스이므로 읽기 전용 유지
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에서 해당 내용을 제거)
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
+ "", // ASIS에서 해당 내용을 '제거'하므로 삽입할 텍스트는 없음
235221
+ currentInstance.#asisEditorView, // 대상 에디터는 ASIS (현재 소스)
235222
+ { from: asisRangeStart, to: asisRangeStart + text.length }, // ASIS에서 '삭제될' 범위
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,33 @@ 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가 삭제한 것을 '삭제' (ASIS에서 제거)
234918
+ button.className = "cm-merge-button revert"; // 'revert' 클래스 사용 (빨간색)
234919
+ button.textContent = "삭제"; // 텍스트 변경
234920
+ } else {
234921
+ // TOBE (오른쪽) 에디터에 붙는 버튼: AI가 추가한 것을 '적용' (ASIS에 반영)
234922
+ button.className = "cm-merge-button accept"; // 'accept' 클래스 사용 (녹색)
234923
+ button.textContent = "← 적용"; // 화살표 방향 변경
234924
+ }
234915
234925
 
234926
+ // 클릭 이벤트 핸들러
234916
234927
  button.addEventListener("click", () => {
234917
- console.log(`버튼 클릭: ${this.isAsisButton ? 'ASIS -> TOBE' : 'TOBE -> ASIS'}`, this.textToApply);
234928
+ console.log(`버튼 클릭: ${this.isAsisButton ? 'ASIS (삭제)' : 'TOBE (적용)'}`, this.textToApply);
234918
234929
  console.log("대상 에디터:", this.targetEditorView === this.hostComponent.asisEditorView ? "ASIS" : "TOBE");
234919
234930
  console.log("대상 범위:", this.diffRange);
234920
234931
 
@@ -234927,22 +234938,13 @@ class MergeButtonWidget extends WidgetType {
234927
234938
  return container;
234928
234939
  }
234929
234940
 
234941
+ // 실제 변경 적용 로직
234930
234942
  applyChanges(text, editorView, range) {
234931
234943
  if (!editorView || !range) {
234932
234944
  console.error("Target editor view or range is undefined.", editorView, range);
234933
234945
  return;
234934
234946
  }
234935
234947
 
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
234948
  editorView.dispatch({
234947
234949
  changes: {
234948
234950
  from: range.from,
@@ -234970,9 +234972,14 @@ class IdeDiff extends HTMLElement {
234970
234972
  _asisScrollHandler = null;
234971
234973
  _tobeScrollHandler = null;
234972
234974
 
234975
+ // MergeButtonWidget에서 접근할 수 있도록 Getter를 공개합니다.
234973
234976
  get asisEditorView() {
234974
234977
  return this.#asisEditorView;
234975
- };
234978
+ }
234979
+ get tobeEditorView() {
234980
+ return this.#tobeEditorView;
234981
+ }
234982
+
234976
234983
 
234977
234984
  constructor() {
234978
234985
  super();
@@ -234982,7 +234989,9 @@ class IdeDiff extends HTMLElement {
234982
234989
  connectedCallback() {
234983
234990
  this.shadowRoot.innerHTML = `
234984
234991
  <style>
234992
+ /* ninegrid CSS 및 필요한 기본 스타일 임포트 */
234985
234993
  @import "https://cdn.jsdelivr.net/npm/ninegrid@${ninegrid.version}/dist/css/ideDiff.css";
234994
+ /* 새로 만든 ideDiff.css 파일 임포트 */
234986
234995
  ${ninegrid.getCustomPath(this, "ideDiff.css")}
234987
234996
  </style>
234988
234997
 
@@ -235053,9 +235062,10 @@ class IdeDiff extends HTMLElement {
235053
235062
  extensions: [
235054
235063
  basicExtensions,
235055
235064
  this.#languageCompartment.of(javascript()),
235056
- EditorState.readOnly.of(true),
235065
+ // ASIS는 읽기 전용으로 유지 (원본 소스) - 필요에 따라 편집 가능하도록 변경 가능
235066
+ EditorState.readOnly.of(false), // 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 추천 소스이므로 읽기 전용 유지
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에서 해당 내용을 제거)
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
+ "", // ASIS에서 해당 내용을 '제거'하므로 삽입할 텍스트는 없음
235217
+ currentInstance.#asisEditorView, // 대상 에디터는 ASIS (현재 소스)
235218
+ { from: asisRangeStart, to: asisRangeStart + text.length }, // ASIS에서 '삭제될' 범위
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,33 @@ 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가 삭제한 것을 '삭제' (ASIS에서 제거)
118
+ button.className = "cm-merge-button revert"; // 'revert' 클래스 사용 (빨간색)
119
+ button.textContent = "삭제"; // 텍스트 변경
120
+ } else {
121
+ // TOBE (오른쪽) 에디터에 붙는 버튼: AI가 추가한 것을 '적용' (ASIS에 반영)
122
+ button.className = "cm-merge-button accept"; // 'accept' 클래스 사용 (녹색)
123
+ button.textContent = "← 적용"; // 화살표 방향 변경
124
+ }
115
125
 
126
+ // 클릭 이벤트 핸들러
116
127
  button.addEventListener("click", () => {
117
- console.log(`버튼 클릭: ${this.isAsisButton ? 'ASIS -> TOBE' : 'TOBE -> ASIS'}`, this.textToApply);
128
+ console.log(`버튼 클릭: ${this.isAsisButton ? 'ASIS (삭제)' : 'TOBE (적용)'}`, this.textToApply);
118
129
  console.log("대상 에디터:", this.targetEditorView === this.hostComponent.asisEditorView ? "ASIS" : "TOBE");
119
130
  console.log("대상 범위:", this.diffRange);
120
131
 
@@ -127,22 +138,13 @@ class MergeButtonWidget extends WidgetType {
127
138
  return container;
128
139
  }
129
140
 
141
+ // 실제 변경 적용 로직
130
142
  applyChanges(text, editorView, range) {
131
143
  if (!editorView || !range) {
132
144
  console.error("Target editor view or range is undefined.", editorView, range);
133
145
  return;
134
146
  }
135
147
 
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
148
  editorView.dispatch({
147
149
  changes: {
148
150
  from: range.from,
@@ -170,9 +172,14 @@ export class IdeDiff extends HTMLElement {
170
172
  _asisScrollHandler = null;
171
173
  _tobeScrollHandler = null;
172
174
 
175
+ // MergeButtonWidget에서 접근할 수 있도록 Getter를 공개합니다.
173
176
  get asisEditorView() {
174
177
  return this.#asisEditorView;
175
- };
178
+ }
179
+ get tobeEditorView() {
180
+ return this.#tobeEditorView;
181
+ }
182
+
176
183
 
177
184
  constructor() {
178
185
  super();
@@ -182,7 +189,9 @@ export class IdeDiff extends HTMLElement {
182
189
  connectedCallback() {
183
190
  this.shadowRoot.innerHTML = `
184
191
  <style>
192
+ /* ninegrid CSS 및 필요한 기본 스타일 임포트 */
185
193
  @import "https://cdn.jsdelivr.net/npm/ninegrid@${ninegrid.version}/dist/css/ideDiff.css";
194
+ /* 새로 만든 ideDiff.css 파일 임포트 */
186
195
  ${ninegrid.getCustomPath(this, "ideDiff.css")}
187
196
  </style>
188
197
 
@@ -253,9 +262,10 @@ export class IdeDiff extends HTMLElement {
253
262
  extensions: [
254
263
  basicExtensions,
255
264
  this.#languageCompartment.of(javascript()),
256
- EditorState.readOnly.of(true),
265
+ // ASIS는 읽기 전용으로 유지 (원본 소스) - 필요에 따라 편집 가능하도록 변경 가능
266
+ EditorState.readOnly.of(false), // 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 추천 소스이므로 읽기 전용 유지
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에서 해당 내용을 제거)
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
+ "", // ASIS에서 해당 내용을 '제거'하므로 삽입할 텍스트는 없음
417
+ currentInstance.#asisEditorView, // 대상 에디터는 ASIS (현재 소스)
418
+ { from: asisRangeStart, to: asisRangeStart + text.length }, // ASIS에서 '삭제될' 범위
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.443.0",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "exports": {
@@ -99,22 +99,33 @@ 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가 삭제한 것을 '삭제' (ASIS에서 제거)
118
+ button.className = "cm-merge-button revert"; // 'revert' 클래스 사용 (빨간색)
119
+ button.textContent = "삭제"; // 텍스트 변경
120
+ } else {
121
+ // TOBE (오른쪽) 에디터에 붙는 버튼: AI가 추가한 것을 '적용' (ASIS에 반영)
122
+ button.className = "cm-merge-button accept"; // 'accept' 클래스 사용 (녹색)
123
+ button.textContent = "← 적용"; // 화살표 방향 변경
124
+ }
115
125
 
126
+ // 클릭 이벤트 핸들러
116
127
  button.addEventListener("click", () => {
117
- console.log(`버튼 클릭: ${this.isAsisButton ? 'ASIS -> TOBE' : 'TOBE -> ASIS'}`, this.textToApply);
128
+ console.log(`버튼 클릭: ${this.isAsisButton ? 'ASIS (삭제)' : 'TOBE (적용)'}`, this.textToApply);
118
129
  console.log("대상 에디터:", this.targetEditorView === this.hostComponent.asisEditorView ? "ASIS" : "TOBE");
119
130
  console.log("대상 범위:", this.diffRange);
120
131
 
@@ -127,22 +138,13 @@ class MergeButtonWidget extends WidgetType {
127
138
  return container;
128
139
  }
129
140
 
141
+ // 실제 변경 적용 로직
130
142
  applyChanges(text, editorView, range) {
131
143
  if (!editorView || !range) {
132
144
  console.error("Target editor view or range is undefined.", editorView, range);
133
145
  return;
134
146
  }
135
147
 
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
148
  editorView.dispatch({
147
149
  changes: {
148
150
  from: range.from,
@@ -170,9 +172,14 @@ export class IdeDiff extends HTMLElement {
170
172
  _asisScrollHandler = null;
171
173
  _tobeScrollHandler = null;
172
174
 
175
+ // MergeButtonWidget에서 접근할 수 있도록 Getter를 공개합니다.
173
176
  get asisEditorView() {
174
177
  return this.#asisEditorView;
175
- };
178
+ }
179
+ get tobeEditorView() {
180
+ return this.#tobeEditorView;
181
+ }
182
+
176
183
 
177
184
  constructor() {
178
185
  super();
@@ -182,7 +189,9 @@ export class IdeDiff extends HTMLElement {
182
189
  connectedCallback() {
183
190
  this.shadowRoot.innerHTML = `
184
191
  <style>
192
+ /* ninegrid CSS 및 필요한 기본 스타일 임포트 */
185
193
  @import "https://cdn.jsdelivr.net/npm/ninegrid@${ninegrid.version}/dist/css/ideDiff.css";
194
+ /* 새로 만든 ideDiff.css 파일 임포트 */
186
195
  ${ninegrid.getCustomPath(this, "ideDiff.css")}
187
196
  </style>
188
197
 
@@ -253,9 +262,10 @@ export class IdeDiff extends HTMLElement {
253
262
  extensions: [
254
263
  basicExtensions,
255
264
  this.#languageCompartment.of(javascript()),
256
- EditorState.readOnly.of(true),
265
+ // ASIS는 읽기 전용으로 유지 (원본 소스) - 필요에 따라 편집 가능하도록 변경 가능
266
+ EditorState.readOnly.of(false), // 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 추천 소스이므로 읽기 전용 유지
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에서 해당 내용을 제거)
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
+ "", // ASIS에서 해당 내용을 '제거'하므로 삽입할 텍스트는 없음
417
+ currentInstance.#asisEditorView, // 대상 에디터는 ASIS (현재 소스)
418
+ { from: asisRangeStart, to: asisRangeStart + text.length }, // ASIS에서 '삭제될' 범위
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
  };