ide-assi 0.437.0 → 0.439.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.
@@ -234824,6 +234824,10 @@ var diffMatchPatchExports = requireDiffMatchPatch();
234824
234824
  const setAsisDecorationsEffect = StateEffect.define();
234825
234825
  const setTobeDecorationsEffect = StateEffect.define();
234826
234826
 
234827
+ // --- 버튼 데코레이션을 위한 새로운 StateEffect 정의 ---
234828
+ const setAsisButtonDecorationsEffect = StateEffect.define();
234829
+ const setTobeButtonDecorationsEffect = StateEffect.define();
234830
+
234827
234831
  // --- Diff 데코레이션을 위한 StateField 정의 ---
234828
234832
  const asisDiffDecorations = StateField.define({
234829
234833
  create() {
@@ -234857,32 +234861,58 @@ const tobeDiffDecorations = StateField.define({
234857
234861
  provide: f => EditorView.decorations.from(f)
234858
234862
  });
234859
234863
 
234864
+ // --- 버튼 데코레이션을 위한 새로운 StateField 정의 ---
234865
+ const asisButtonDecorations = StateField.define({
234866
+ create() {
234867
+ return Decoration.none;
234868
+ },
234869
+ update(decorations, tr) {
234870
+ decorations = decorations.map(tr.changes);
234871
+ for (let effect of tr.effects) {
234872
+ if (effect.is(setAsisButtonDecorationsEffect)) {
234873
+ return effect.value;
234874
+ }
234875
+ }
234876
+ return decorations;
234877
+ },
234878
+ provide: f => EditorView.decorations.from(f)
234879
+ });
234880
+
234881
+ const tobeButtonDecorations = StateField.define({
234882
+ create() {
234883
+ return Decoration.none;
234884
+ },
234885
+ update(decorations, tr) {
234886
+ decorations = decorations.map(tr.changes);
234887
+ for (let effect of tr.effects) {
234888
+ if (effect.is(setTobeButtonDecorationsEffect)) {
234889
+ return effect.value;
234890
+ }
234891
+ }
234892
+ return decorations;
234893
+ },
234894
+ provide: f => EditorView.decorations.from(f)
234895
+ });
234896
+
234860
234897
 
234861
234898
  // IdeDiff 클래스 외부 (파일 상단 or 하단)에 추가
234862
234899
  class MergeButtonWidget extends WidgetType {
234863
- // ⭐️ diffRange는 변경이 발생할 대상 에디터의 범위입니다.
234864
- // ⭐️ isAsisButton: ASIS 에디터 쪽에 붙는 버튼인가? (true면 ASIS -> TOBE 적용)
234865
- // ⭐️ isAsisButton이 false면 TOBE 에디터 쪽에 붙는 버튼 (TOBE -> ASIS 되돌리기)
234866
234900
  constructor(isAsisButton, textToApply, targetEditorView, diffRange, hostComponent) {
234867
234901
  super();
234868
- this.isAsisButton = isAsisButton; // 이 버튼이 ASIS 에디터에 붙는 버튼인가 (true) TOBE 에디터에 붙는 버튼인가 (false)
234869
- this.textToApply = textToApply; // 적용할 텍스트
234870
- this.targetEditorView = targetEditorView; // 텍스트를 적용할 에디터 뷰 (상대편 에디터)
234871
- this.diffRange = diffRange; // 대상 에디터에서 변경이 일어날 정확한 from/to 오프셋
234872
- this.hostComponent = hostComponent; // IdeDiff 인스턴스 참조
234902
+ this.isAsisButton = isAsisButton;
234903
+ this.textToApply = textToApply;
234904
+ this.targetEditorView = targetEditorView;
234905
+ this.diffRange = diffRange;
234906
+ this.hostComponent = hostComponent;
234873
234907
  }
234874
234908
 
234875
- // 위젯이 차지할 공간을 텍스트 줄에 할당할지 여부. false로 설정하여 버튼이 줄 사이에 끼어들지 않도록 함.
234876
234909
  eq(other) { return false; }
234877
234910
 
234878
- // 위젯의 DOM 요소를 생성합니다.
234879
234911
  toDOM(view) {
234880
234912
  const button = document.createElement("button");
234881
- // 버튼 클래스 및 텍스트는 버튼의 위치(ASIS/TOBE)에 따라 결정됩니다.
234882
234913
  button.className = `cm-merge-button ${this.isAsisButton ? 'accept' : 'revert'}`;
234883
- button.textContent = this.isAsisButton ? "→ 적용" : "← 되돌리기"; // ASIS 버튼: TOBE로 적용, TOBE 버튼: ASIS로 되돌리기
234914
+ button.textContent = this.isAsisButton ? "→ 적용" : "← 되돌리기";
234884
234915
 
234885
- // 클릭 이벤트 핸들러
234886
234916
  button.addEventListener("click", () => {
234887
234917
  console.log(`버튼 클릭: ${this.isAsisButton ? 'ASIS -> TOBE' : 'TOBE -> ASIS'}`, this.textToApply);
234888
234918
  console.log("대상 에디터:", this.targetEditorView === this.hostComponent.#asisEditorView ? "ASIS" : "TOBE");
@@ -234897,13 +234927,22 @@ class MergeButtonWidget extends WidgetType {
234897
234927
  return container;
234898
234928
  }
234899
234929
 
234900
- // 실제 변경 적용 로직
234901
234930
  applyChanges(text, editorView, range) {
234902
234931
  if (!editorView || !range) {
234903
234932
  console.error("Target editor view or range is undefined.", editorView, range);
234904
234933
  return;
234905
234934
  }
234906
234935
 
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
+
234907
234946
  editorView.dispatch({
234908
234947
  changes: {
234909
234948
  from: range.from,
@@ -234912,9 +234951,6 @@ class MergeButtonWidget extends WidgetType {
234912
234951
  }
234913
234952
  });
234914
234953
 
234915
- // 변경 후 Diff를 다시 계산하고 데코레이션을 업데이트합니다.
234916
- // requestAnimationFrame으로 감싸서 다음 렌더링 사이클에서 Diff 계산이 이루어지도록 합니다.
234917
- // 이렇게 하면 UI 블로킹을 줄일 수 있습니다.
234918
234954
  requestAnimationFrame(() => {
234919
234955
  this.hostComponent.recalculateDiff();
234920
234956
  });
@@ -234943,65 +234979,8 @@ class IdeDiff extends HTMLElement {
234943
234979
  connectedCallback() {
234944
234980
  this.shadowRoot.innerHTML = `
234945
234981
  <style>
234946
- /* ninegrid CSS 및 필요한 기본 스타일 */
234947
234982
  @import "https://cdn.jsdelivr.net/npm/ninegrid@${ninegrid.version}/dist/css/ideDiff.css";
234948
234983
  ${ninegrid.getCustomPath(this, "ideDiff.css")}
234949
-
234950
- /* --- 추가된 CSS 규칙 (버튼 및 선택 관련) --- */
234951
- .cm-line {
234952
- position: relative;
234953
- }
234954
- .cm-merge-button-container {
234955
- position: absolute;
234956
- right: 5px;
234957
- top: 50%;
234958
- transform: translateY(-50%);
234959
- z-index: 10;
234960
- display: flex;
234961
- gap: 5px;
234962
- }
234963
- .cm-merge-button {
234964
- background-color: #f0f0f0;
234965
- border: 1px solid #ccc;
234966
- border-radius: 3px;
234967
- padding: 2px 6px;
234968
- cursor: pointer;
234969
- font-size: 0.8em;
234970
- line-height: 1;
234971
- white-space: nowrap;
234972
- opacity: 0.7;
234973
- transition: opacity 0.2s ease-in-out;
234974
- }
234975
- .cm-merge-button:hover {
234976
- opacity: 1;
234977
- background-color: #e0e0e0;
234978
- }
234979
- .cm-merge-button.accept {
234980
- background-color: #4CAF50;
234981
- color: white;
234982
- border-color: #4CAF50;
234983
- }
234984
- .cm-merge-button.revert {
234985
- background-color: #f44336;
234986
- color: white;
234987
- border-color: #f44336;
234988
- }
234989
- /* Diff 데코레이션 CSS (ideDiff.css에 없으면 여기에 추가) */
234990
- .cm-inserted-line-bg { background-color: #e6ffed; border-left: 3px solid #66bb6a; }
234991
- .cm-deleted-line-bg { background-color: #ffebe9; border-left: 3px solid #ef5350; }
234992
-
234993
- /* CodeMirror 선택 스타일 (ideDiff.css에 없으면 여기에 추가) */
234994
- .cm-selectionBackground {
234995
- background-color: #d7d4f9 !important;
234996
- }
234997
- .cm-editor ::selection {
234998
- background-color: #d7d4f9 !important;
234999
- color: inherit !important;
235000
- }
235001
- .cm-editor::-moz-selection {
235002
- background-color: #d7d4f9 !important;
235003
- color: inherit !important;
235004
- }
235005
234984
  </style>
235006
234985
 
235007
234986
  <div class="wrapper">
@@ -235058,22 +235037,22 @@ class IdeDiff extends HTMLElement {
235058
235037
  ...historyKeymap,
235059
235038
  ...lintKeymap,
235060
235039
  ...completionKeymap,
235061
- indentWithTab, // ⭐️ 함수가 아닌 확장 자체를 전달
235062
- selectAll // ⭐️ 함수가 아닌 확장 자체를 전달
235040
+ indentWithTab,
235041
+ selectAll
235063
235042
  ]),
235064
235043
  syntaxHighlighting(defaultHighlightStyle),
235065
235044
  autocompletion(),
235066
235045
  ];
235067
235046
 
235068
- // ASIS 에디터 뷰 초기화
235069
235047
  this.#asisEditorView = new EditorView({
235070
235048
  state: EditorState.create({
235071
235049
  doc: '',
235072
235050
  extensions: [
235073
235051
  basicExtensions,
235074
235052
  this.#languageCompartment.of(javascript()),
235075
- EditorState.readOnly.of(true), // ASIS는 읽기 전용 유지
235053
+ EditorState.readOnly.of(true),
235076
235054
  asisDiffDecorations,
235055
+ asisButtonDecorations, // ⭐️ 새로운 StateField 추가
235077
235056
  EditorView.updateListener.of((update) => {
235078
235057
  if (update.view.contentDOM.firstChild && !update.view._initialAsisContentLoaded) {
235079
235058
  update.view._initialAsisContentLoaded = true;
@@ -235085,15 +235064,14 @@ class IdeDiff extends HTMLElement {
235085
235064
  parent: this.#asisEditorEl
235086
235065
  });
235087
235066
 
235088
- // TOBE 에디터 뷰 초기화
235089
235067
  this.#tobeEditorView = new EditorView({
235090
235068
  state: EditorState.create({
235091
235069
  doc: '',
235092
235070
  extensions: [
235093
235071
  basicExtensions,
235094
235072
  this.#languageCompartment.of(javascript()),
235095
- // EditorState.readOnly.of(true), // TOBE는 편집 가능하도록 주석 처리 유지
235096
235073
  tobeDiffDecorations,
235074
+ tobeButtonDecorations, // ⭐️ 새로운 StateField 추가
235097
235075
  EditorView.updateListener.of((update) => {
235098
235076
  if (update.view.contentDOM.firstChild && !update.view._initialTobeContentLoaded) {
235099
235077
  update.view._initialTobeContentLoaded = true;
@@ -235155,13 +235133,15 @@ class IdeDiff extends HTMLElement {
235155
235133
  dmp.diff_cleanupSemantic(diffs);
235156
235134
  dmp.diff_charsToLines_(diffs, lineArray);
235157
235135
 
235158
- console.log("Calculated Diffs:", diffs); // Diff 결과 확인용
235136
+ console.log("Calculated Diffs:", diffs);
235159
235137
 
235160
235138
  const asisLineBuilder = new RangeSetBuilder();
235161
235139
  const tobeLineBuilder = new RangeSetBuilder();
235140
+ const asisButtonBuilder = new RangeSetBuilder(); // ⭐️ 새로운 빌더
235141
+ const tobeButtonBuilder = new RangeSetBuilder(); // ⭐️ 새로운 빌더
235162
235142
 
235163
- let asisCursor = 0; // ASIS 텍스트에서의 현재 오프셋
235164
- let tobeCursor = 0; // TOBE 텍스트에서의 현재 오프셋
235143
+ let asisCursor = 0;
235144
+ let tobeCursor = 0;
235165
235145
 
235166
235146
  const insertedLineDeco = Decoration.line({ class: "cm-inserted-line-bg" });
235167
235147
  const deletedLineDeco = Decoration.line({ class: "cm-deleted-line-bg" });
@@ -235171,7 +235151,6 @@ class IdeDiff extends HTMLElement {
235171
235151
  for (const [op, text] of diffs) {
235172
235152
  const len = text.length;
235173
235153
 
235174
- // 각 diff op 이전에 현재 커서 위치를 저장
235175
235154
  const asisRangeStart = asisCursor;
235176
235155
  const tobeRangeStart = tobeCursor;
235177
235156
 
@@ -235186,20 +235165,22 @@ class IdeDiff extends HTMLElement {
235186
235165
  tobeCursor += tobeLines[i].length + (i < tobeLines.length - 1 ? 1 : 0);
235187
235166
  }
235188
235167
 
235189
- // ⭐️ TOBE 에디터에 버튼 추가: TOBE의 추가 내용을 ASIS로 '되돌리기' (ASIS에서 삭제)
235190
- // 즉, TOBE에서 삽입된 내용을 ASIS에서 '없애는' 작업
235191
- tobeLineBuilder.add(
235168
+ // ⭐️ TOBE 에디터에 버튼 추가: TOBE의 추가 내용을 ASIS로 '되돌리기' (ASIS에서 제거)
235169
+ // TOBE 해당 Diff가 끝나는 지점에 버튼을 붙이는 것이 자연스럽습니다.
235170
+ // tobeRangeStart는 Diff 청크의 시작 오프셋입니다.
235171
+ // 버튼을 Line Decoration과 같은 위치에 추가하되, 별도의 builder 사용
235172
+ tobeButtonBuilder.add(
235192
235173
  tobeRangeStart, // TOBE에서의 해당 Diff 청크 시작 오프셋
235193
235174
  tobeRangeStart,
235194
235175
  Decoration.widget({
235195
235176
  widget: new MergeButtonWidget(
235196
235177
  false, // 이 버튼은 TOBE 에디터에 붙는 버튼 (되돌리기)
235197
- "", // 텍스트를 ""로 삽입하면 삭제 효과 (ASIS에서 없앨 내용)
235178
+ "", // ASIS에서 해당 내용을 제거하므로 삽입할 텍스트는 없음 (즉, 삭제)
235198
235179
  currentInstance.#asisEditorView, // 대상 에디터는 ASIS
235199
- { from: asisRangeStart, to: asisRangeStart + 0 }, // ASIS에서의 대상 범위 (삽입 지점)
235180
+ { from: asisRangeStart, to: asisRangeStart + text.length }, // ASIS에서 '삭제될' 범위
235200
235181
  currentInstance
235201
235182
  ),
235202
- side: 1 // 텍스트 뒤에 삽입
235183
+ side: 1 // 텍스트 뒤에 삽입 (이전에 `side: -1`로 시도했다면 `-1`이 우선순위가 더 높습니다.)
235203
235184
  })
235204
235185
  );
235205
235186
  break;
@@ -235214,9 +235195,8 @@ class IdeDiff extends HTMLElement {
235214
235195
  asisCursor += asisLines[i].length + (i < asisLines.length - 1 ? 1 : 0);
235215
235196
  }
235216
235197
 
235217
- // ⭐️ ASIS 에디터에 버튼 추가: ASIS의 삭제 내용을 TOBE로 '적용' (TOBE에 삽입)
235218
- // 즉, ASIS에서 삭제된 내용을 TOBE에 '넣는' 작업
235219
- asisLineBuilder.add(
235198
+ // ⭐️ ASIS 에디터에 버튼 추가: ASIS의 삭제 내용을 TOBE로 '적용' (TOBE에 해당 내용 삽입)
235199
+ asisButtonBuilder.add(
235220
235200
  asisRangeStart, // ASIS에서의 해당 Diff 청크 시작 오프셋
235221
235201
  asisRangeStart,
235222
235202
  Decoration.widget({
@@ -235224,7 +235204,7 @@ class IdeDiff extends HTMLElement {
235224
235204
  true, // 이 버튼은 ASIS 에디터에 붙는 버튼 (적용)
235225
235205
  text, // ASIS에서 삭제된 내용을 TOBE에 삽입
235226
235206
  currentInstance.#tobeEditorView, // 대상 에디터는 TOBE
235227
- { from: tobeRangeStart, to: tobeRangeStart + 0 }, // TOBE에서의 대상 범위 (삽입 지점)
235207
+ { from: tobeRangeStart, to: tobeRangeStart + 0 }, // TOBE에서 '삽입될' 위치
235228
235208
  currentInstance
235229
235209
  ),
235230
235210
  side: 1 // 텍스트 뒤에 삽입
@@ -235241,7 +235221,9 @@ class IdeDiff extends HTMLElement {
235241
235221
 
235242
235222
  return {
235243
235223
  asisDecorations: asisLineBuilder.finish(),
235244
- tobeDecorations: tobeLineBuilder.finish()
235224
+ tobeDecorations: tobeLineBuilder.finish(),
235225
+ asisButtonDecorations: asisButtonBuilder.finish(), // ⭐️ 추가 반환
235226
+ tobeButtonDecorations: tobeButtonBuilder.finish() // ⭐️ 추가 반환
235245
235227
  };
235246
235228
  };
235247
235229
 
@@ -235249,13 +235231,19 @@ class IdeDiff extends HTMLElement {
235249
235231
  const asisDoc = this.#asisEditorView.state.doc.toString();
235250
235232
  const tobeDoc = this.#tobeEditorView.state.doc.toString();
235251
235233
 
235252
- const { asisDecorations, tobeDecorations } = this.#applyDiffDecorations(asisDoc, tobeDoc);
235234
+ const { asisDecorations, tobeDecorations, asisButtonDecorations, tobeButtonDecorations } = this.#applyDiffDecorations(asisDoc, tobeDoc);
235253
235235
 
235254
235236
  this.#asisEditorView.dispatch({
235255
- effects: [setAsisDecorationsEffect.of(asisDecorations)]
235237
+ effects: [
235238
+ setAsisDecorationsEffect.of(asisDecorations),
235239
+ setAsisButtonDecorationsEffect.of(asisButtonDecorations) // ⭐️ Effect 추가
235240
+ ]
235256
235241
  });
235257
235242
  this.#tobeEditorView.dispatch({
235258
- effects: [setTobeDecorationsEffect.of(tobeDecorations)]
235243
+ effects: [
235244
+ setTobeDecorationsEffect.of(tobeDecorations),
235245
+ setTobeButtonDecorationsEffect.of(tobeButtonDecorations) // ⭐️ Effect 추가
235246
+ ]
235259
235247
  });
235260
235248
  };
235261
235249
 
@@ -235291,13 +235279,19 @@ class IdeDiff extends HTMLElement {
235291
235279
  });
235292
235280
 
235293
235281
  requestAnimationFrame(() => {
235294
- const { asisDecorations, tobeDecorations } = this.#applyDiffDecorations(src1, src2);
235282
+ const { asisDecorations, tobeDecorations, asisButtonDecorations, tobeButtonDecorations } = this.#applyDiffDecorations(src1, src2);
235295
235283
 
235296
235284
  this.#asisEditorView.dispatch({
235297
- effects: [setAsisDecorationsEffect.of(asisDecorations)]
235285
+ effects: [
235286
+ setAsisDecorationsEffect.of(asisDecorations),
235287
+ setAsisButtonDecorationsEffect.of(asisButtonDecorations)
235288
+ ]
235298
235289
  });
235299
235290
  this.#tobeEditorView.dispatch({
235300
- effects: [setTobeDecorationsEffect.of(tobeDecorations)]
235291
+ effects: [
235292
+ setTobeDecorationsEffect.of(tobeDecorations),
235293
+ setTobeButtonDecorationsEffect.of(tobeButtonDecorations)
235294
+ ]
235301
235295
  });
235302
235296
 
235303
235297
  requestAnimationFrame(() => {