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