ide-assi 0.333.0 → 0.334.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.
@@ -234747,15 +234747,49 @@ function requireDiffMatchPatch () {
234747
234747
 
234748
234748
  var diffMatchPatchExports = requireDiffMatchPatch();
234749
234749
 
234750
- // ... (나머지 IdeDiff 클래스 코드는 동일) ...
234750
+ // Diff 데코레이션을 위한 StateField 정의 (asis 에디터용)
234751
+ const asisDiffDecorations = StateField.define({
234752
+ create() { return Decoration.none; }, // 초기 상태
234753
+ update(decorations, tr) {
234754
+ // 트랜잭션에 포함된 Effects를 처리하여 데코레이션을 업데이트
234755
+ // `#applyDiffDecorations` 함수에서 데코레이션 업데이트 요청을 보낼 때 사용
234756
+ return tr.effects.reduce((currentDecos, effect) => {
234757
+ if (effect.is(setAsisDecorationsEffect)) {
234758
+ return effect.value;
234759
+ }
234760
+ return currentDecos;
234761
+ }, decorations);
234762
+ },
234763
+ // 데코레이션을 뷰에 제공
234764
+ provide: f => EditorView.decorations.from(f)
234765
+ });
234766
+
234767
+ // Diff 데코레이션을 위한 StateField 정의 (tobe 에디터용)
234768
+ const tobeDiffDecorations = StateField.define({
234769
+ create() { return Decoration.none; },
234770
+ update(decorations, tr) {
234771
+ return tr.effects.reduce((currentDecos, effect) => {
234772
+ if (effect.is(setTobeDecorationsEffect)) {
234773
+ return effect.value;
234774
+ }
234775
+ return currentDecos;
234776
+ }, decorations);
234777
+ },
234778
+ provide: f => EditorView.decorations.from(f)
234779
+ });
234780
+
234781
+ // 데코레이션 업데이트를 위한 Effect (트랜잭션에 포함시켜 상태 변경 알림)
234782
+ const setAsisDecorationsEffect = EditorState.define.effect();
234783
+ const setTobeDecorationsEffect = EditorState.define.effect();
234784
+
234751
234785
 
234752
234786
  class IdeDiff extends HTMLElement {
234753
- #asisEditorView; // asis 패널의 CodeMirror EditorView 인스턴스
234754
- #tobeEditorView; // tobe 패널의 CodeMirror EditorView 인스턴스
234755
- #asisEditorEl; // asis 에디터를 렌더링할 DOM 요소
234756
- #tobeEditorEl; // tobe 에디터를 렌더링할 DOM 요소
234787
+ #asisEditorView;
234788
+ #tobeEditorView;
234789
+ #asisEditorEl;
234790
+ #tobeEditorEl;
234757
234791
 
234758
- #languageCompartment = new Compartment(); // 언어 확장을 동적으로 변경하기 위한 Compartment
234792
+ #languageCompartment = new Compartment();
234759
234793
 
234760
234794
  constructor() {
234761
234795
  super();
@@ -234779,27 +234813,29 @@ class IdeDiff extends HTMLElement {
234779
234813
  .panel {
234780
234814
  flex: 1; /* 패널들이 남은 공간을 채우도록 */
234781
234815
  overflow: hidden; /* CodeMirror EditorView 자체가 스크롤을 처리 */
234782
- /* position: relative; */ /* CodeMirror가 자체적으로 관리하므로 필요 없을 수 있음 */
234783
234816
  min-width: 0; /* Flexbox 아이템이 content 때문에 늘어나는 것을 방지 */
234784
234817
  }
234785
234818
  .cm-editor {
234786
234819
  height: 100%; /* EditorView가 부모 div의 높이를 채우도록 */
234787
234820
  }
234788
234821
 
234789
- /* Diff 시각화를 위한 기본 스타일 (나중에 데코레이션으로 더 정교하게) */
234790
- .cm-line.cm-deleted-line {
234791
- background-color: #ffeef0; /* 삭제된 배경 */
234792
- }
234793
- .cm-line.cm-inserted-line {
234794
- background-color: #e6ffed; /* 삽입된 배경 */
234822
+ /* Diff 시각화를 위한 CSS 클래스 */
234823
+ /* 줄 전체 배경색 */
234824
+ .cm-inserted-line-bg { background-color: #e6ffe6; } /* 연한 녹색 */
234825
+ .cm-deleted-line-bg { background-color: #ffe6e6; } /* 연한 빨간색 */
234826
+
234827
+ /* 인라인(단어/문자) 변경 강조 */
234828
+ .cm-inserted-inline {
234829
+ background-color: #90ee90; /* 밝은 녹색 */
234830
+ font-weight: bold;
234795
234831
  }
234796
234832
  .cm-deleted-inline {
234797
- background-color: #ffcccc; /* 인라인 삭제 */
234833
+ background-color: #ff9999; /* 밝은 빨간색 */
234798
234834
  text-decoration: line-through;
234835
+ font-weight: bold;
234799
234836
  }
234800
- .cm-inserted-inline {
234801
- background-color: #ccffcc; /* 인라인 삽입 */
234802
- }
234837
+ /* 선택적: 동일하지만 이동된 줄 강조 (복잡함) */
234838
+ /* .cm-moved-line-bg {} */
234803
234839
  </style>
234804
234840
 
234805
234841
  <div class="wrapper">
@@ -234825,58 +234861,59 @@ class IdeDiff extends HTMLElement {
234825
234861
 
234826
234862
  // CodeMirror 확장 기본 설정
234827
234863
  const basicExtensions = [
234828
- lineNumbers(), // 줄 번호
234829
- highlightSpecialChars(), // 특수 문자 강조 (예: 공백)
234830
- history(), // 실행 취소/다시 실행
234831
- drawSelection(), // 선택 영역 표시
234832
- dropCursor(), // 드래그 시 커서 위치
234833
- EditorState.allowMultipleSelections.of(true), // 다중 선택 허용
234834
- indentOnInput(), // 입력 시 자동 들여쓰기
234835
- bracketMatching(), // 괄호 짝 맞추기
234836
- highlightActiveLine(), // 현재 줄 강조
234837
- highlightSelectionMatches(), // 선택된 텍스트와 일치하는 부분 강조
234864
+ lineNumbers(),
234865
+ highlightSpecialChars(),
234866
+ history(),
234867
+ drawSelection(),
234868
+ dropCursor(),
234869
+ EditorState.allowMultipleSelections.of(true),
234870
+ indentOnInput(),
234871
+ bracketMatching(),
234872
+ highlightActiveLine(),
234873
+ highlightSelectionMatches(),
234838
234874
  keymap.of([
234839
- ...defaultKeymap, // 기본 키맵 (Enter, Backspace 등)
234840
- ...searchKeymap, // 검색 관련 키맵
234841
- ...historyKeymap, // undo/redo 키맵
234842
- ...lintKeymap, // 린트 관련 키맵
234843
- ...completionKeymap, // 자동 완성 키맵
234844
- indentWithTab // 탭으로 들여쓰기 (필요시)
234875
+ ...defaultKeymap,
234876
+ ...searchKeymap,
234877
+ ...historyKeymap,
234878
+ ...lintKeymap,
234879
+ ...completionKeymap,
234880
+ indentWithTab,
234881
+ selectAll // selectAll 추가
234845
234882
  ]),
234846
- syntaxHighlighting(defaultHighlightStyle, { fallback: true }), // 기본 구문 하이라이팅
234847
- autocompletion(), // 자동 완성
234848
- // EditorState.readOnly.of(true) // 기본적으로 읽기 전용으로 설정
234883
+ syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
234884
+ autocompletion(),
234849
234885
  ];
234850
234886
 
234851
234887
  // asis 에디터 생성 (읽기 전용)
234852
234888
  this.#asisEditorView = new EditorView({
234853
234889
  state: EditorState.create({
234854
- doc: '', // 초기 내용 비워둠
234890
+ doc: '',
234855
234891
  extensions: [
234856
234892
  basicExtensions,
234857
- javascript(), // JS 언어 모드 (필요에 따라 변경)
234893
+ javascript(), // JS 언어 모드 (기본)
234858
234894
  EditorState.readOnly.of(true), // asis는 읽기 전용
234859
- this.#languageCompartment.of(javascript()) // 언어 변경을 위한 compartment
234895
+ this.#languageCompartment.of(javascript()), // 언어 변경 compartment
234896
+ asisDiffDecorations // asis 에디터에 Diff 데코레이션 필드 추가
234860
234897
  ]
234861
234898
  }),
234862
234899
  parent: this.#asisEditorEl
234863
234900
  });
234864
234901
 
234865
- // tobe 에디터 생성 (읽기 전용, 또는 편집 가능하게 할 수도 있음)
234902
+ // tobe 에디터 생성 (읽기 전용, 필요 편집 가능하게 설정)
234866
234903
  this.#tobeEditorView = new EditorView({
234867
234904
  state: EditorState.create({
234868
- doc: '', // 초기 내용 비워둠
234905
+ doc: '',
234869
234906
  extensions: [
234870
234907
  basicExtensions,
234871
- javascript(), // JS 언어 모드 (필요에 따라 변경)
234872
- EditorState.readOnly.of(true), // tobe도 읽기 전용으로 설정 (필요시 false)
234873
- this.#languageCompartment.of(javascript()) // 언어 변경을 위한 compartment
234908
+ javascript(), // JS 언어 모드 (기본)
234909
+ EditorState.readOnly.of(true), // tobe도 읽기 전용
234910
+ this.#languageCompartment.of(javascript()), // 언어 변경 compartment
234911
+ tobeDiffDecorations // tobe 에디터에 Diff 데코레이션 필드 추가
234874
234912
  ]
234875
234913
  }),
234876
234914
  parent: this.#tobeEditorEl
234877
234915
  });
234878
234916
 
234879
- // 스크롤 동기화 설정
234880
234917
  this.#setupScrollSync();
234881
234918
  };
234882
234919
 
@@ -234903,44 +234940,101 @@ class IdeDiff extends HTMLElement {
234903
234940
  });
234904
234941
  };
234905
234942
 
234906
- // Diff 계산하고 에디터에 적용하는 메서드
234907
- #renderDiff = (asisSrc, tobeSrc) => {
234943
+ // ⭐️⭐️⭐️ Diff 데코레이션 적용 로직 구현 ⭐️⭐️⭐️
234944
+ #applyDiffDecorations = (asisSrc, tobeSrc) => {
234908
234945
  const dmp = new diffMatchPatchExports.diff_match_patch();
234909
234946
  const diffs = dmp.diff_main(asisSrc, tobeSrc);
234910
234947
  dmp.diff_cleanupSemantic(diffs);
234911
234948
 
234912
- // TODO: diffs 결과를 바탕으로 CodeMirror 데코레이션(Decoration)을 생성하고 에디터에 적용하는 로직 구현
234913
- // 부분은 CodeMirror의 Decoration, StateField, ViewPlugin 등을 이해하고 구현해야 합니다.
234914
- // 각 줄에 대한 변경 상태(삽입/삭제/동일)를 판단하고, 인라인 변경(단어 단위)도 처리해야 합니다.
234915
- // 예를 들어:
234916
- // const asisDecorations = [];
234917
- // const tobeDecorations = [];
234918
- // let asisCursor = 0;
234919
- // let tobeCursor = 0;
234920
- // for (const [op, text] of diffs) {
234921
- // const len = text.length;
234922
- // if (op === diff_match_patch.DIFF_INSERT) {
234923
- // // tobe 쪽에 삽입된 부분 데코레이션 추가
234924
- // tobeDecorations.push(Decoration.mark({class: "cm-inserted-inline"}).range(tobeCursor, tobeCursor + len));
234925
- // tobeCursor += len;
234926
- // } else if (op === diff_match_patch.DIFF_DELETE) {
234927
- // // asis 쪽에 삭제된 부분 데코레이션 추가
234928
- // asisDecorations.push(Decoration.mark({class: "cm-deleted-inline"}).range(asisCursor, asisCursor + len));
234929
- // asisCursor += len;
234930
- // } else { // DIFF_EQUAL
234931
- // asisCursor += len;
234932
- // tobeCursor += len;
234933
- // }
234934
- // }
234935
- // 에디터 상태를 업데이트하고 데코레이션을 적용하는 복잡한 로직이 필요합니다.
234936
- // 이 예시에서는 생략하지만, 실제 구현 시 핵심이 됩니다.
234937
-
234938
- // 현재는 단순히 텍스트만 업데이트
234949
+ const asisBuilder = new RangeSetBuilder();
234950
+ const tobeBuilder = new RangeSetBuilder();
234951
+
234952
+ let asisCursor = 0; // asis 에디터에서의 현재 텍스트 오프셋
234953
+ let tobeCursor = 0; // tobe 에디터에서의 현재 텍스트 오프셋
234954
+
234955
+ // 단위 데코레이션을 위해 줄 시작 위치를 추적
234956
+ const asisLineStartMap = new Map();
234957
+ const tobeLineStartMap = new Map();
234958
+
234959
+ // 텍스트에 대한 줄 시작 위치 미리 계산
234960
+ let currentPos = 0;
234961
+ for (const line of asisSrc.split('\n')) {
234962
+ asisLineStartMap.set(currentPos, true);
234963
+ currentPos += line.length + 1; // +1은 줄바꿈 문자 포함
234964
+ }
234965
+ currentPos = 0;
234966
+ for (const line of tobeSrc.split('\n')) {
234967
+ tobeLineStartMap.set(currentPos, true);
234968
+ currentPos += line.length + 1;
234969
+ }
234970
+
234971
+ for (const [op, text] of diffs) {
234972
+ const len = text.length;
234973
+
234974
+ switch (op) {
234975
+ case diffMatchPatchExports.diff_match_patch.DIFF_INSERT: // Added text
234976
+ // tobe 쪽에 인라인 데코레이션 추가
234977
+ tobeBuilder.add(
234978
+ tobeCursor, tobeCursor + len,
234979
+ Decoration.mark({ class: "cm-inserted-inline" })
234980
+ );
234981
+
234982
+ // tobe 쪽에 줄 전체 데코레이션 추가 (삽입된 줄)
234983
+ // text가 여러 줄일 수 있으므로 각 줄에 적용
234984
+ const tobeLines = text.split('\n');
234985
+ let currentLineOffset = tobeCursor;
234986
+ for(let i = 0; i < tobeLines.length; i++) {
234987
+ // 각 줄의 시작 위치를 찾기
234988
+ const lineStart = tobeEditorView.state.doc.lineAt(currentLineOffset).from;
234989
+ // 만약 다음 줄이 있다면 해당 줄의 끝까지, 마지막 줄이라면 텍스트의 끝까지
234990
+ const lineEnd = i === tobeLines.length - 1 ? currentLineOffset + tobeLines[i].length : tobeEditorView.state.doc.lineAt(currentLineOffset).to;
234991
+ tobeBuilder.add(
234992
+ lineStart, lineEnd, // 줄의 실제 시작부터 끝까지
234993
+ Decoration.line({ class: "cm-inserted-line-bg" })
234994
+ );
234995
+ currentLineOffset += tobeLines[i].length + 1; // 다음 줄 시작 위치로 이동
234996
+ }
234997
+
234998
+
234999
+ tobeCursor += len;
235000
+ break;
235001
+
235002
+ case diffMatchPatchExports.diff_match_patch.DIFF_DELETE: // Deleted text
235003
+ // asis 쪽에 인라인 데코레이션 추가
235004
+ asisBuilder.add(
235005
+ asisCursor, asisCursor + len,
235006
+ Decoration.mark({ class: "cm-deleted-inline" })
235007
+ );
235008
+
235009
+ // asis 쪽에 줄 전체 데코레이션 추가 (삭제된 줄)
235010
+ const asisLines = text.split('\n');
235011
+ let currentAsisLineOffset = asisCursor;
235012
+ for(let i = 0; i < asisLines.length; i++) {
235013
+ const lineStart = asisEditorView.state.doc.lineAt(currentAsisLineOffset).from;
235014
+ const lineEnd = i === asisLines.length - 1 ? currentAsisLineOffset + asisLines[i].length : asisEditorView.state.doc.lineAt(currentAsisLineOffset).to;
235015
+ asisBuilder.add(
235016
+ lineStart, lineEnd,
235017
+ Decoration.line({ class: "cm-deleted-line-bg" })
235018
+ );
235019
+ currentAsisLineOffset += asisLines[i].length + 1;
235020
+ }
235021
+
235022
+ asisCursor += len;
235023
+ break;
235024
+
235025
+ case diffMatchPatchExports.diff_match_patch.DIFF_EQUAL: // Unchanged text
235026
+ asisCursor += len;
235027
+ tobeCursor += len;
235028
+ break;
235029
+ }
235030
+ }
235031
+
235032
+ // 에디터 뷰에 데코레이션 업데이트 요청 디스패치
234939
235033
  this.#asisEditorView.dispatch({
234940
- changes: { from: 0, to: this.#asisEditorView.state.doc.length, insert: asisSrc }
235034
+ effects: setAsisDecorationsEffect.of(asisBuilder.finish())
234941
235035
  });
234942
235036
  this.#tobeEditorView.dispatch({
234943
- changes: { from: 0, to: this.#tobeEditorView.state.doc.length, insert: tobeSrc }
235037
+ effects: setTobeDecorationsEffect.of(tobeBuilder.finish())
234944
235038
  });
234945
235039
  };
234946
235040
 
@@ -234957,13 +235051,15 @@ class IdeDiff extends HTMLElement {
234957
235051
  langExtension = javascript();
234958
235052
  break;
234959
235053
  // case 'html':
234960
- // langExtension = html(); // @codemirror/lang-html 임포트 필요
235054
+ // import { html } from "@codemirror/lang-html"; // 상단에 임포트 필요
235055
+ // langExtension = html();
234961
235056
  // break;
234962
235057
  // case 'css':
234963
- // langExtension = css(); // @codemirror/lang-css 임포트 필요
235058
+ // import { css } from "@codemirror/lang-css"; // 상단에 임포트 필요
235059
+ // langExtension = css();
234964
235060
  // break;
234965
235061
  default:
234966
- langExtension = javascript(); // 기본값
235062
+ langExtension = javascript();
234967
235063
  }
234968
235064
 
234969
235065
  // 언어 확장 업데이트
@@ -234974,11 +235070,19 @@ class IdeDiff extends HTMLElement {
234974
235070
  effects: this.#languageCompartment.reconfigure(langExtension)
234975
235071
  });
234976
235072
 
234977
- this.#renderDiff(src1, src2);
235073
+ // 텍스트 내용 업데이트
235074
+ this.#asisEditorView.dispatch({
235075
+ changes: { from: 0, to: this.#asisEditorView.state.doc.length, insert: src1 }
235076
+ });
235077
+ this.#tobeEditorView.dispatch({
235078
+ changes: { from: 0, to: this.#tobeEditorView.state.doc.length, insert: src2 }
235079
+ });
235080
+
235081
+ // Diff 데코레이션 적용
235082
+ this.#applyDiffDecorations(src1, src2);
234978
235083
  };
234979
235084
 
234980
235085
  disconnectedCallback() {
234981
- // 컴포넌트가 DOM에서 제거될 때 에디터 인스턴스 정리
234982
235086
  if (this.#asisEditorView) {
234983
235087
  this.#asisEditorView.destroy();
234984
235088
  }