ide-assi 0.335.0 → 0.337.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.
- package/dist/bundle.cjs.js +35 -68
- package/dist/bundle.esm.js +35 -68
- package/dist/components/ideDiff.js +35 -68
- package/package.json +1 -1
- package/src/components/ideDiff.js +35 -68
package/dist/bundle.cjs.js
CHANGED
|
@@ -234751,12 +234751,12 @@ function requireDiffMatchPatch () {
|
|
|
234751
234751
|
|
|
234752
234752
|
var diffMatchPatchExports = requireDiffMatchPatch();
|
|
234753
234753
|
|
|
234754
|
+
// --- 여기서부터 수정된 부분 ---
|
|
234755
|
+
|
|
234754
234756
|
// Diff 데코레이션을 위한 StateField 정의 (asis 에디터용)
|
|
234755
234757
|
const asisDiffDecorations = StateField.define({
|
|
234756
|
-
create() { return Decoration.none; },
|
|
234758
|
+
create() { return Decoration.none; },
|
|
234757
234759
|
update(decorations, tr) {
|
|
234758
|
-
// 트랜잭션에 포함된 Effects를 처리하여 데코레이션을 업데이트
|
|
234759
|
-
// `#applyDiffDecorations` 함수에서 데코레이션 업데이트 요청을 보낼 때 사용
|
|
234760
234760
|
return tr.effects.reduce((currentDecos, effect) => {
|
|
234761
234761
|
if (effect.is(setAsisDecorationsEffect)) {
|
|
234762
234762
|
return effect.value;
|
|
@@ -234764,7 +234764,6 @@ const asisDiffDecorations = StateField.define({
|
|
|
234764
234764
|
return currentDecos;
|
|
234765
234765
|
}, decorations);
|
|
234766
234766
|
},
|
|
234767
|
-
// 데코레이션을 뷰에 제공
|
|
234768
234767
|
provide: f => EditorView.decorations.from(f)
|
|
234769
234768
|
});
|
|
234770
234769
|
|
|
@@ -234783,9 +234782,11 @@ const tobeDiffDecorations = StateField.define({
|
|
|
234783
234782
|
});
|
|
234784
234783
|
|
|
234785
234784
|
// 데코레이션 업데이트를 위한 Effect (트랜잭션에 포함시켜 상태 변경 알림)
|
|
234786
|
-
|
|
234787
|
-
const
|
|
234785
|
+
// ⭐️ 이 부분이 수정되었습니다: .define.effect() -> .defineEffect()
|
|
234786
|
+
const setAsisDecorationsEffect = EditorState.defineEffect();
|
|
234787
|
+
const setTobeDecorationsEffect = EditorState.defineEffect();
|
|
234788
234788
|
|
|
234789
|
+
// --- 여기까지 수정된 부분 ---
|
|
234789
234790
|
|
|
234790
234791
|
class IdeDiff extends HTMLElement {
|
|
234791
234792
|
#asisEditorView;
|
|
@@ -234838,8 +234839,6 @@ class IdeDiff extends HTMLElement {
|
|
|
234838
234839
|
text-decoration: line-through;
|
|
234839
234840
|
font-weight: bold;
|
|
234840
234841
|
}
|
|
234841
|
-
/* 선택적: 동일하지만 이동된 줄 강조 (복잡함) */
|
|
234842
|
-
/* .cm-moved-line-bg {} */
|
|
234843
234842
|
</style>
|
|
234844
234843
|
|
|
234845
234844
|
<div class="wrapper">
|
|
@@ -234863,7 +234862,6 @@ class IdeDiff extends HTMLElement {
|
|
|
234863
234862
|
return;
|
|
234864
234863
|
}
|
|
234865
234864
|
|
|
234866
|
-
// CodeMirror 확장 기본 설정
|
|
234867
234865
|
const basicExtensions = [
|
|
234868
234866
|
lineNumbers(),
|
|
234869
234867
|
highlightSpecialChars(),
|
|
@@ -234882,37 +234880,35 @@ class IdeDiff extends HTMLElement {
|
|
|
234882
234880
|
...lintKeymap,
|
|
234883
234881
|
...completionKeymap,
|
|
234884
234882
|
indentWithTab,
|
|
234885
|
-
selectAll
|
|
234883
|
+
selectAll
|
|
234886
234884
|
]),
|
|
234887
234885
|
syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
|
|
234888
234886
|
autocompletion(),
|
|
234889
234887
|
];
|
|
234890
234888
|
|
|
234891
|
-
// asis 에디터 생성 (읽기 전용)
|
|
234892
234889
|
this.#asisEditorView = new EditorView({
|
|
234893
234890
|
state: EditorState.create({
|
|
234894
234891
|
doc: '',
|
|
234895
234892
|
extensions: [
|
|
234896
234893
|
basicExtensions,
|
|
234897
|
-
javascript(),
|
|
234898
|
-
EditorState.readOnly.of(true),
|
|
234899
|
-
this.#languageCompartment.of(javascript()),
|
|
234900
|
-
asisDiffDecorations
|
|
234894
|
+
javascript(),
|
|
234895
|
+
EditorState.readOnly.of(true),
|
|
234896
|
+
this.#languageCompartment.of(javascript()),
|
|
234897
|
+
asisDiffDecorations
|
|
234901
234898
|
]
|
|
234902
234899
|
}),
|
|
234903
234900
|
parent: this.#asisEditorEl
|
|
234904
234901
|
});
|
|
234905
234902
|
|
|
234906
|
-
// tobe 에디터 생성 (읽기 전용, 필요 시 편집 가능하게 설정)
|
|
234907
234903
|
this.#tobeEditorView = new EditorView({
|
|
234908
234904
|
state: EditorState.create({
|
|
234909
234905
|
doc: '',
|
|
234910
234906
|
extensions: [
|
|
234911
234907
|
basicExtensions,
|
|
234912
|
-
javascript(),
|
|
234913
|
-
EditorState.readOnly.of(true),
|
|
234914
|
-
this.#languageCompartment.of(javascript()),
|
|
234915
|
-
tobeDiffDecorations
|
|
234908
|
+
javascript(),
|
|
234909
|
+
EditorState.readOnly.of(true),
|
|
234910
|
+
this.#languageCompartment.of(javascript()),
|
|
234911
|
+
tobeDiffDecorations
|
|
234916
234912
|
]
|
|
234917
234913
|
}),
|
|
234918
234914
|
parent: this.#tobeEditorEl
|
|
@@ -234944,7 +234940,6 @@ class IdeDiff extends HTMLElement {
|
|
|
234944
234940
|
});
|
|
234945
234941
|
};
|
|
234946
234942
|
|
|
234947
|
-
// ⭐️⭐️⭐️ Diff 데코레이션 적용 로직 구현 ⭐️⭐️⭐️
|
|
234948
234943
|
#applyDiffDecorations = (asisSrc, tobeSrc) => {
|
|
234949
234944
|
const dmp = new diffMatchPatchExports.diff_match_patch();
|
|
234950
234945
|
const diffs = dmp.diff_main(asisSrc, tobeSrc);
|
|
@@ -234953,69 +234948,52 @@ class IdeDiff extends HTMLElement {
|
|
|
234953
234948
|
const asisBuilder = new RangeSetBuilder();
|
|
234954
234949
|
const tobeBuilder = new RangeSetBuilder();
|
|
234955
234950
|
|
|
234956
|
-
let asisCursor = 0;
|
|
234957
|
-
let tobeCursor = 0;
|
|
234958
|
-
|
|
234959
|
-
// 줄 단위 데코레이션을 위해 줄 시작 위치를 추적
|
|
234960
|
-
const asisLineStartMap = new Map();
|
|
234961
|
-
const tobeLineStartMap = new Map();
|
|
234962
|
-
|
|
234963
|
-
// 각 텍스트에 대한 줄 시작 위치 미리 계산
|
|
234964
|
-
let currentPos = 0;
|
|
234965
|
-
for (const line of asisSrc.split('\n')) {
|
|
234966
|
-
asisLineStartMap.set(currentPos, true);
|
|
234967
|
-
currentPos += line.length + 1; // +1은 줄바꿈 문자 포함
|
|
234968
|
-
}
|
|
234969
|
-
currentPos = 0;
|
|
234970
|
-
for (const line of tobeSrc.split('\n')) {
|
|
234971
|
-
tobeLineStartMap.set(currentPos, true);
|
|
234972
|
-
currentPos += line.length + 1;
|
|
234973
|
-
}
|
|
234951
|
+
let asisCursor = 0;
|
|
234952
|
+
let tobeCursor = 0;
|
|
234974
234953
|
|
|
234975
234954
|
for (const [op, text] of diffs) {
|
|
234976
234955
|
const len = text.length;
|
|
234977
234956
|
|
|
234978
234957
|
switch (op) {
|
|
234979
|
-
case diffMatchPatchExports.diff_match_patch.DIFF_INSERT:
|
|
234980
|
-
// tobe 쪽에 인라인 데코레이션 추가
|
|
234958
|
+
case diffMatchPatchExports.diff_match_patch.DIFF_INSERT:
|
|
234981
234959
|
tobeBuilder.add(
|
|
234982
234960
|
tobeCursor, tobeCursor + len,
|
|
234983
234961
|
Decoration.mark({ class: "cm-inserted-inline" })
|
|
234984
234962
|
);
|
|
234985
234963
|
|
|
234986
|
-
//
|
|
234987
|
-
// text가 여러 줄일 수 있으므로 각 줄에 적용
|
|
234964
|
+
// Inserted lines background
|
|
234988
234965
|
const tobeLines = text.split('\n');
|
|
234989
|
-
let
|
|
234966
|
+
let currentTobeLineOffset = tobeCursor;
|
|
234990
234967
|
for(let i = 0; i < tobeLines.length; i++) {
|
|
234991
|
-
//
|
|
234992
|
-
const lineStart = tobeEditorView.state.doc.lineAt(
|
|
234993
|
-
//
|
|
234994
|
-
|
|
234968
|
+
// Get line start/end from the *current* editor view's document
|
|
234969
|
+
const lineStart = this.#tobeEditorView.state.doc.lineAt(currentTobeLineOffset).from;
|
|
234970
|
+
// For the last segment of a multi-line insertion, the end is just current offset + segment length
|
|
234971
|
+
// Otherwise, it's the end of the current line in the doc.
|
|
234972
|
+
const lineEnd = i === tobeLines.length - 1 ? currentTobeLineOffset + tobeLines[i].length : this.#tobeEditorView.state.doc.lineAt(currentTobeLineOffset).to;
|
|
234973
|
+
|
|
234995
234974
|
tobeBuilder.add(
|
|
234996
|
-
lineStart, lineEnd,
|
|
234975
|
+
lineStart, lineEnd,
|
|
234997
234976
|
Decoration.line({ class: "cm-inserted-line-bg" })
|
|
234998
234977
|
);
|
|
234999
|
-
|
|
234978
|
+
currentTobeLineOffset += tobeLines[i].length + 1; // Move to next line start
|
|
235000
234979
|
}
|
|
235001
234980
|
|
|
235002
|
-
|
|
235003
234981
|
tobeCursor += len;
|
|
235004
234982
|
break;
|
|
235005
234983
|
|
|
235006
|
-
case diffMatchPatchExports.diff_match_patch.DIFF_DELETE:
|
|
235007
|
-
// asis 쪽에 인라인 데코레이션 추가
|
|
234984
|
+
case diffMatchPatchExports.diff_match_patch.DIFF_DELETE:
|
|
235008
234985
|
asisBuilder.add(
|
|
235009
234986
|
asisCursor, asisCursor + len,
|
|
235010
234987
|
Decoration.mark({ class: "cm-deleted-inline" })
|
|
235011
234988
|
);
|
|
235012
234989
|
|
|
235013
|
-
//
|
|
234990
|
+
// Deleted lines background
|
|
235014
234991
|
const asisLines = text.split('\n');
|
|
235015
234992
|
let currentAsisLineOffset = asisCursor;
|
|
235016
234993
|
for(let i = 0; i < asisLines.length; i++) {
|
|
235017
|
-
const lineStart = asisEditorView.state.doc.lineAt(currentAsisLineOffset).from;
|
|
235018
|
-
const lineEnd = i === asisLines.length - 1 ? currentAsisLineOffset + asisLines[i].length : asisEditorView.state.doc.lineAt(currentAsisLineOffset).to;
|
|
234994
|
+
const lineStart = this.#asisEditorView.state.doc.lineAt(currentAsisLineOffset).from;
|
|
234995
|
+
const lineEnd = i === asisLines.length - 1 ? currentAsisLineOffset + asisLines[i].length : this.#asisEditorView.state.doc.lineAt(currentAsisLineOffset).to;
|
|
234996
|
+
|
|
235019
234997
|
asisBuilder.add(
|
|
235020
234998
|
lineStart, lineEnd,
|
|
235021
234999
|
Decoration.line({ class: "cm-deleted-line-bg" })
|
|
@@ -235026,14 +235004,13 @@ class IdeDiff extends HTMLElement {
|
|
|
235026
235004
|
asisCursor += len;
|
|
235027
235005
|
break;
|
|
235028
235006
|
|
|
235029
|
-
case diffMatchPatchExports.diff_match_patch.DIFF_EQUAL:
|
|
235007
|
+
case diffMatchPatchExports.diff_match_patch.DIFF_EQUAL:
|
|
235030
235008
|
asisCursor += len;
|
|
235031
235009
|
tobeCursor += len;
|
|
235032
235010
|
break;
|
|
235033
235011
|
}
|
|
235034
235012
|
}
|
|
235035
235013
|
|
|
235036
|
-
// 에디터 뷰에 데코레이션 업데이트 요청 디스패치
|
|
235037
235014
|
this.#asisEditorView.dispatch({
|
|
235038
235015
|
effects: setAsisDecorationsEffect.of(asisBuilder.finish())
|
|
235039
235016
|
});
|
|
@@ -235048,25 +235025,15 @@ class IdeDiff extends HTMLElement {
|
|
|
235048
235025
|
return;
|
|
235049
235026
|
}
|
|
235050
235027
|
|
|
235051
|
-
// 언어 변경 (선택 사항, 필요 시 활성화)
|
|
235052
235028
|
let langExtension;
|
|
235053
235029
|
switch(language) {
|
|
235054
235030
|
case 'javascript':
|
|
235055
235031
|
langExtension = javascript();
|
|
235056
235032
|
break;
|
|
235057
|
-
// case 'html':
|
|
235058
|
-
// import { html } from "@codemirror/lang-html"; // 상단에 임포트 필요
|
|
235059
|
-
// langExtension = html();
|
|
235060
|
-
// break;
|
|
235061
|
-
// case 'css':
|
|
235062
|
-
// import { css } from "@codemirror/lang-css"; // 상단에 임포트 필요
|
|
235063
|
-
// langExtension = css();
|
|
235064
|
-
// break;
|
|
235065
235033
|
default:
|
|
235066
235034
|
langExtension = javascript();
|
|
235067
235035
|
}
|
|
235068
235036
|
|
|
235069
|
-
// 언어 확장 업데이트
|
|
235070
235037
|
this.#asisEditorView.dispatch({
|
|
235071
235038
|
effects: this.#languageCompartment.reconfigure(langExtension)
|
|
235072
235039
|
});
|
package/dist/bundle.esm.js
CHANGED
|
@@ -234747,12 +234747,12 @@ function requireDiffMatchPatch () {
|
|
|
234747
234747
|
|
|
234748
234748
|
var diffMatchPatchExports = requireDiffMatchPatch();
|
|
234749
234749
|
|
|
234750
|
+
// --- 여기서부터 수정된 부분 ---
|
|
234751
|
+
|
|
234750
234752
|
// Diff 데코레이션을 위한 StateField 정의 (asis 에디터용)
|
|
234751
234753
|
const asisDiffDecorations = StateField.define({
|
|
234752
|
-
create() { return Decoration.none; },
|
|
234754
|
+
create() { return Decoration.none; },
|
|
234753
234755
|
update(decorations, tr) {
|
|
234754
|
-
// 트랜잭션에 포함된 Effects를 처리하여 데코레이션을 업데이트
|
|
234755
|
-
// `#applyDiffDecorations` 함수에서 데코레이션 업데이트 요청을 보낼 때 사용
|
|
234756
234756
|
return tr.effects.reduce((currentDecos, effect) => {
|
|
234757
234757
|
if (effect.is(setAsisDecorationsEffect)) {
|
|
234758
234758
|
return effect.value;
|
|
@@ -234760,7 +234760,6 @@ const asisDiffDecorations = StateField.define({
|
|
|
234760
234760
|
return currentDecos;
|
|
234761
234761
|
}, decorations);
|
|
234762
234762
|
},
|
|
234763
|
-
// 데코레이션을 뷰에 제공
|
|
234764
234763
|
provide: f => EditorView.decorations.from(f)
|
|
234765
234764
|
});
|
|
234766
234765
|
|
|
@@ -234779,9 +234778,11 @@ const tobeDiffDecorations = StateField.define({
|
|
|
234779
234778
|
});
|
|
234780
234779
|
|
|
234781
234780
|
// 데코레이션 업데이트를 위한 Effect (트랜잭션에 포함시켜 상태 변경 알림)
|
|
234782
|
-
|
|
234783
|
-
const
|
|
234781
|
+
// ⭐️ 이 부분이 수정되었습니다: .define.effect() -> .defineEffect()
|
|
234782
|
+
const setAsisDecorationsEffect = EditorState.defineEffect();
|
|
234783
|
+
const setTobeDecorationsEffect = EditorState.defineEffect();
|
|
234784
234784
|
|
|
234785
|
+
// --- 여기까지 수정된 부분 ---
|
|
234785
234786
|
|
|
234786
234787
|
class IdeDiff extends HTMLElement {
|
|
234787
234788
|
#asisEditorView;
|
|
@@ -234834,8 +234835,6 @@ class IdeDiff extends HTMLElement {
|
|
|
234834
234835
|
text-decoration: line-through;
|
|
234835
234836
|
font-weight: bold;
|
|
234836
234837
|
}
|
|
234837
|
-
/* 선택적: 동일하지만 이동된 줄 강조 (복잡함) */
|
|
234838
|
-
/* .cm-moved-line-bg {} */
|
|
234839
234838
|
</style>
|
|
234840
234839
|
|
|
234841
234840
|
<div class="wrapper">
|
|
@@ -234859,7 +234858,6 @@ class IdeDiff extends HTMLElement {
|
|
|
234859
234858
|
return;
|
|
234860
234859
|
}
|
|
234861
234860
|
|
|
234862
|
-
// CodeMirror 확장 기본 설정
|
|
234863
234861
|
const basicExtensions = [
|
|
234864
234862
|
lineNumbers(),
|
|
234865
234863
|
highlightSpecialChars(),
|
|
@@ -234878,37 +234876,35 @@ class IdeDiff extends HTMLElement {
|
|
|
234878
234876
|
...lintKeymap,
|
|
234879
234877
|
...completionKeymap,
|
|
234880
234878
|
indentWithTab,
|
|
234881
|
-
selectAll
|
|
234879
|
+
selectAll
|
|
234882
234880
|
]),
|
|
234883
234881
|
syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
|
|
234884
234882
|
autocompletion(),
|
|
234885
234883
|
];
|
|
234886
234884
|
|
|
234887
|
-
// asis 에디터 생성 (읽기 전용)
|
|
234888
234885
|
this.#asisEditorView = new EditorView({
|
|
234889
234886
|
state: EditorState.create({
|
|
234890
234887
|
doc: '',
|
|
234891
234888
|
extensions: [
|
|
234892
234889
|
basicExtensions,
|
|
234893
|
-
javascript(),
|
|
234894
|
-
EditorState.readOnly.of(true),
|
|
234895
|
-
this.#languageCompartment.of(javascript()),
|
|
234896
|
-
asisDiffDecorations
|
|
234890
|
+
javascript(),
|
|
234891
|
+
EditorState.readOnly.of(true),
|
|
234892
|
+
this.#languageCompartment.of(javascript()),
|
|
234893
|
+
asisDiffDecorations
|
|
234897
234894
|
]
|
|
234898
234895
|
}),
|
|
234899
234896
|
parent: this.#asisEditorEl
|
|
234900
234897
|
});
|
|
234901
234898
|
|
|
234902
|
-
// tobe 에디터 생성 (읽기 전용, 필요 시 편집 가능하게 설정)
|
|
234903
234899
|
this.#tobeEditorView = new EditorView({
|
|
234904
234900
|
state: EditorState.create({
|
|
234905
234901
|
doc: '',
|
|
234906
234902
|
extensions: [
|
|
234907
234903
|
basicExtensions,
|
|
234908
|
-
javascript(),
|
|
234909
|
-
EditorState.readOnly.of(true),
|
|
234910
|
-
this.#languageCompartment.of(javascript()),
|
|
234911
|
-
tobeDiffDecorations
|
|
234904
|
+
javascript(),
|
|
234905
|
+
EditorState.readOnly.of(true),
|
|
234906
|
+
this.#languageCompartment.of(javascript()),
|
|
234907
|
+
tobeDiffDecorations
|
|
234912
234908
|
]
|
|
234913
234909
|
}),
|
|
234914
234910
|
parent: this.#tobeEditorEl
|
|
@@ -234940,7 +234936,6 @@ class IdeDiff extends HTMLElement {
|
|
|
234940
234936
|
});
|
|
234941
234937
|
};
|
|
234942
234938
|
|
|
234943
|
-
// ⭐️⭐️⭐️ Diff 데코레이션 적용 로직 구현 ⭐️⭐️⭐️
|
|
234944
234939
|
#applyDiffDecorations = (asisSrc, tobeSrc) => {
|
|
234945
234940
|
const dmp = new diffMatchPatchExports.diff_match_patch();
|
|
234946
234941
|
const diffs = dmp.diff_main(asisSrc, tobeSrc);
|
|
@@ -234949,69 +234944,52 @@ class IdeDiff extends HTMLElement {
|
|
|
234949
234944
|
const asisBuilder = new RangeSetBuilder();
|
|
234950
234945
|
const tobeBuilder = new RangeSetBuilder();
|
|
234951
234946
|
|
|
234952
|
-
let asisCursor = 0;
|
|
234953
|
-
let tobeCursor = 0;
|
|
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
|
-
}
|
|
234947
|
+
let asisCursor = 0;
|
|
234948
|
+
let tobeCursor = 0;
|
|
234970
234949
|
|
|
234971
234950
|
for (const [op, text] of diffs) {
|
|
234972
234951
|
const len = text.length;
|
|
234973
234952
|
|
|
234974
234953
|
switch (op) {
|
|
234975
|
-
case diffMatchPatchExports.diff_match_patch.DIFF_INSERT:
|
|
234976
|
-
// tobe 쪽에 인라인 데코레이션 추가
|
|
234954
|
+
case diffMatchPatchExports.diff_match_patch.DIFF_INSERT:
|
|
234977
234955
|
tobeBuilder.add(
|
|
234978
234956
|
tobeCursor, tobeCursor + len,
|
|
234979
234957
|
Decoration.mark({ class: "cm-inserted-inline" })
|
|
234980
234958
|
);
|
|
234981
234959
|
|
|
234982
|
-
//
|
|
234983
|
-
// text가 여러 줄일 수 있으므로 각 줄에 적용
|
|
234960
|
+
// Inserted lines background
|
|
234984
234961
|
const tobeLines = text.split('\n');
|
|
234985
|
-
let
|
|
234962
|
+
let currentTobeLineOffset = tobeCursor;
|
|
234986
234963
|
for(let i = 0; i < tobeLines.length; i++) {
|
|
234987
|
-
//
|
|
234988
|
-
const lineStart = tobeEditorView.state.doc.lineAt(
|
|
234989
|
-
//
|
|
234990
|
-
|
|
234964
|
+
// Get line start/end from the *current* editor view's document
|
|
234965
|
+
const lineStart = this.#tobeEditorView.state.doc.lineAt(currentTobeLineOffset).from;
|
|
234966
|
+
// For the last segment of a multi-line insertion, the end is just current offset + segment length
|
|
234967
|
+
// Otherwise, it's the end of the current line in the doc.
|
|
234968
|
+
const lineEnd = i === tobeLines.length - 1 ? currentTobeLineOffset + tobeLines[i].length : this.#tobeEditorView.state.doc.lineAt(currentTobeLineOffset).to;
|
|
234969
|
+
|
|
234991
234970
|
tobeBuilder.add(
|
|
234992
|
-
lineStart, lineEnd,
|
|
234971
|
+
lineStart, lineEnd,
|
|
234993
234972
|
Decoration.line({ class: "cm-inserted-line-bg" })
|
|
234994
234973
|
);
|
|
234995
|
-
|
|
234974
|
+
currentTobeLineOffset += tobeLines[i].length + 1; // Move to next line start
|
|
234996
234975
|
}
|
|
234997
234976
|
|
|
234998
|
-
|
|
234999
234977
|
tobeCursor += len;
|
|
235000
234978
|
break;
|
|
235001
234979
|
|
|
235002
|
-
case diffMatchPatchExports.diff_match_patch.DIFF_DELETE:
|
|
235003
|
-
// asis 쪽에 인라인 데코레이션 추가
|
|
234980
|
+
case diffMatchPatchExports.diff_match_patch.DIFF_DELETE:
|
|
235004
234981
|
asisBuilder.add(
|
|
235005
234982
|
asisCursor, asisCursor + len,
|
|
235006
234983
|
Decoration.mark({ class: "cm-deleted-inline" })
|
|
235007
234984
|
);
|
|
235008
234985
|
|
|
235009
|
-
//
|
|
234986
|
+
// Deleted lines background
|
|
235010
234987
|
const asisLines = text.split('\n');
|
|
235011
234988
|
let currentAsisLineOffset = asisCursor;
|
|
235012
234989
|
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;
|
|
234990
|
+
const lineStart = this.#asisEditorView.state.doc.lineAt(currentAsisLineOffset).from;
|
|
234991
|
+
const lineEnd = i === asisLines.length - 1 ? currentAsisLineOffset + asisLines[i].length : this.#asisEditorView.state.doc.lineAt(currentAsisLineOffset).to;
|
|
234992
|
+
|
|
235015
234993
|
asisBuilder.add(
|
|
235016
234994
|
lineStart, lineEnd,
|
|
235017
234995
|
Decoration.line({ class: "cm-deleted-line-bg" })
|
|
@@ -235022,14 +235000,13 @@ class IdeDiff extends HTMLElement {
|
|
|
235022
235000
|
asisCursor += len;
|
|
235023
235001
|
break;
|
|
235024
235002
|
|
|
235025
|
-
case diffMatchPatchExports.diff_match_patch.DIFF_EQUAL:
|
|
235003
|
+
case diffMatchPatchExports.diff_match_patch.DIFF_EQUAL:
|
|
235026
235004
|
asisCursor += len;
|
|
235027
235005
|
tobeCursor += len;
|
|
235028
235006
|
break;
|
|
235029
235007
|
}
|
|
235030
235008
|
}
|
|
235031
235009
|
|
|
235032
|
-
// 에디터 뷰에 데코레이션 업데이트 요청 디스패치
|
|
235033
235010
|
this.#asisEditorView.dispatch({
|
|
235034
235011
|
effects: setAsisDecorationsEffect.of(asisBuilder.finish())
|
|
235035
235012
|
});
|
|
@@ -235044,25 +235021,15 @@ class IdeDiff extends HTMLElement {
|
|
|
235044
235021
|
return;
|
|
235045
235022
|
}
|
|
235046
235023
|
|
|
235047
|
-
// 언어 변경 (선택 사항, 필요 시 활성화)
|
|
235048
235024
|
let langExtension;
|
|
235049
235025
|
switch(language) {
|
|
235050
235026
|
case 'javascript':
|
|
235051
235027
|
langExtension = javascript();
|
|
235052
235028
|
break;
|
|
235053
|
-
// case 'html':
|
|
235054
|
-
// import { html } from "@codemirror/lang-html"; // 상단에 임포트 필요
|
|
235055
|
-
// langExtension = html();
|
|
235056
|
-
// break;
|
|
235057
|
-
// case 'css':
|
|
235058
|
-
// import { css } from "@codemirror/lang-css"; // 상단에 임포트 필요
|
|
235059
|
-
// langExtension = css();
|
|
235060
|
-
// break;
|
|
235061
235029
|
default:
|
|
235062
235030
|
langExtension = javascript();
|
|
235063
235031
|
}
|
|
235064
235032
|
|
|
235065
|
-
// 언어 확장 업데이트
|
|
235066
235033
|
this.#asisEditorView.dispatch({
|
|
235067
235034
|
effects: this.#languageCompartment.reconfigure(langExtension)
|
|
235068
235035
|
});
|
|
@@ -24,12 +24,12 @@ import { autocompletion, completionKeymap } from "@codemirror/autocomplete";
|
|
|
24
24
|
// Diff 로직을 위해 diff-match-patch 사용
|
|
25
25
|
import { diff_match_patch } from 'diff-match-patch';
|
|
26
26
|
|
|
27
|
+
// --- 여기서부터 수정된 부분 ---
|
|
28
|
+
|
|
27
29
|
// Diff 데코레이션을 위한 StateField 정의 (asis 에디터용)
|
|
28
30
|
const asisDiffDecorations = StateField.define({
|
|
29
|
-
create() { return Decoration.none; },
|
|
31
|
+
create() { return Decoration.none; },
|
|
30
32
|
update(decorations, tr) {
|
|
31
|
-
// 트랜잭션에 포함된 Effects를 처리하여 데코레이션을 업데이트
|
|
32
|
-
// `#applyDiffDecorations` 함수에서 데코레이션 업데이트 요청을 보낼 때 사용
|
|
33
33
|
return tr.effects.reduce((currentDecos, effect) => {
|
|
34
34
|
if (effect.is(setAsisDecorationsEffect)) {
|
|
35
35
|
return effect.value;
|
|
@@ -37,7 +37,6 @@ const asisDiffDecorations = StateField.define({
|
|
|
37
37
|
return currentDecos;
|
|
38
38
|
}, decorations);
|
|
39
39
|
},
|
|
40
|
-
// 데코레이션을 뷰에 제공
|
|
41
40
|
provide: f => EditorView.decorations.from(f)
|
|
42
41
|
});
|
|
43
42
|
|
|
@@ -56,9 +55,11 @@ const tobeDiffDecorations = StateField.define({
|
|
|
56
55
|
});
|
|
57
56
|
|
|
58
57
|
// 데코레이션 업데이트를 위한 Effect (트랜잭션에 포함시켜 상태 변경 알림)
|
|
59
|
-
|
|
60
|
-
const
|
|
58
|
+
// ⭐️ 이 부분이 수정되었습니다: .define.effect() -> .defineEffect()
|
|
59
|
+
const setAsisDecorationsEffect = EditorState.defineEffect();
|
|
60
|
+
const setTobeDecorationsEffect = EditorState.defineEffect();
|
|
61
61
|
|
|
62
|
+
// --- 여기까지 수정된 부분 ---
|
|
62
63
|
|
|
63
64
|
export class IdeDiff extends HTMLElement {
|
|
64
65
|
#asisEditorView;
|
|
@@ -111,8 +112,6 @@ export class IdeDiff extends HTMLElement {
|
|
|
111
112
|
text-decoration: line-through;
|
|
112
113
|
font-weight: bold;
|
|
113
114
|
}
|
|
114
|
-
/* 선택적: 동일하지만 이동된 줄 강조 (복잡함) */
|
|
115
|
-
/* .cm-moved-line-bg {} */
|
|
116
115
|
</style>
|
|
117
116
|
|
|
118
117
|
<div class="wrapper">
|
|
@@ -136,7 +135,6 @@ export class IdeDiff extends HTMLElement {
|
|
|
136
135
|
return;
|
|
137
136
|
}
|
|
138
137
|
|
|
139
|
-
// CodeMirror 확장 기본 설정
|
|
140
138
|
const basicExtensions = [
|
|
141
139
|
lineNumbers(),
|
|
142
140
|
highlightSpecialChars(),
|
|
@@ -155,37 +153,35 @@ export class IdeDiff extends HTMLElement {
|
|
|
155
153
|
...lintKeymap,
|
|
156
154
|
...completionKeymap,
|
|
157
155
|
indentWithTab,
|
|
158
|
-
selectAll
|
|
156
|
+
selectAll
|
|
159
157
|
]),
|
|
160
158
|
syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
|
|
161
159
|
autocompletion(),
|
|
162
160
|
];
|
|
163
161
|
|
|
164
|
-
// asis 에디터 생성 (읽기 전용)
|
|
165
162
|
this.#asisEditorView = new EditorView({
|
|
166
163
|
state: EditorState.create({
|
|
167
164
|
doc: '',
|
|
168
165
|
extensions: [
|
|
169
166
|
basicExtensions,
|
|
170
|
-
javascript(),
|
|
171
|
-
EditorState.readOnly.of(true),
|
|
172
|
-
this.#languageCompartment.of(javascript()),
|
|
173
|
-
asisDiffDecorations
|
|
167
|
+
javascript(),
|
|
168
|
+
EditorState.readOnly.of(true),
|
|
169
|
+
this.#languageCompartment.of(javascript()),
|
|
170
|
+
asisDiffDecorations
|
|
174
171
|
]
|
|
175
172
|
}),
|
|
176
173
|
parent: this.#asisEditorEl
|
|
177
174
|
});
|
|
178
175
|
|
|
179
|
-
// tobe 에디터 생성 (읽기 전용, 필요 시 편집 가능하게 설정)
|
|
180
176
|
this.#tobeEditorView = new EditorView({
|
|
181
177
|
state: EditorState.create({
|
|
182
178
|
doc: '',
|
|
183
179
|
extensions: [
|
|
184
180
|
basicExtensions,
|
|
185
|
-
javascript(),
|
|
186
|
-
EditorState.readOnly.of(true),
|
|
187
|
-
this.#languageCompartment.of(javascript()),
|
|
188
|
-
tobeDiffDecorations
|
|
181
|
+
javascript(),
|
|
182
|
+
EditorState.readOnly.of(true),
|
|
183
|
+
this.#languageCompartment.of(javascript()),
|
|
184
|
+
tobeDiffDecorations
|
|
189
185
|
]
|
|
190
186
|
}),
|
|
191
187
|
parent: this.#tobeEditorEl
|
|
@@ -217,7 +213,6 @@ export class IdeDiff extends HTMLElement {
|
|
|
217
213
|
});
|
|
218
214
|
};
|
|
219
215
|
|
|
220
|
-
// ⭐️⭐️⭐️ Diff 데코레이션 적용 로직 구현 ⭐️⭐️⭐️
|
|
221
216
|
#applyDiffDecorations = (asisSrc, tobeSrc) => {
|
|
222
217
|
const dmp = new diff_match_patch();
|
|
223
218
|
const diffs = dmp.diff_main(asisSrc, tobeSrc);
|
|
@@ -226,69 +221,52 @@ export class IdeDiff extends HTMLElement {
|
|
|
226
221
|
const asisBuilder = new RangeSetBuilder();
|
|
227
222
|
const tobeBuilder = new RangeSetBuilder();
|
|
228
223
|
|
|
229
|
-
let asisCursor = 0;
|
|
230
|
-
let tobeCursor = 0;
|
|
231
|
-
|
|
232
|
-
// 줄 단위 데코레이션을 위해 줄 시작 위치를 추적
|
|
233
|
-
const asisLineStartMap = new Map();
|
|
234
|
-
const tobeLineStartMap = new Map();
|
|
235
|
-
|
|
236
|
-
// 각 텍스트에 대한 줄 시작 위치 미리 계산
|
|
237
|
-
let currentPos = 0;
|
|
238
|
-
for (const line of asisSrc.split('\n')) {
|
|
239
|
-
asisLineStartMap.set(currentPos, true);
|
|
240
|
-
currentPos += line.length + 1; // +1은 줄바꿈 문자 포함
|
|
241
|
-
}
|
|
242
|
-
currentPos = 0;
|
|
243
|
-
for (const line of tobeSrc.split('\n')) {
|
|
244
|
-
tobeLineStartMap.set(currentPos, true);
|
|
245
|
-
currentPos += line.length + 1;
|
|
246
|
-
}
|
|
224
|
+
let asisCursor = 0;
|
|
225
|
+
let tobeCursor = 0;
|
|
247
226
|
|
|
248
227
|
for (const [op, text] of diffs) {
|
|
249
228
|
const len = text.length;
|
|
250
229
|
|
|
251
230
|
switch (op) {
|
|
252
|
-
case diff_match_patch.DIFF_INSERT:
|
|
253
|
-
// tobe 쪽에 인라인 데코레이션 추가
|
|
231
|
+
case diff_match_patch.DIFF_INSERT:
|
|
254
232
|
tobeBuilder.add(
|
|
255
233
|
tobeCursor, tobeCursor + len,
|
|
256
234
|
Decoration.mark({ class: "cm-inserted-inline" })
|
|
257
235
|
);
|
|
258
236
|
|
|
259
|
-
//
|
|
260
|
-
// text가 여러 줄일 수 있으므로 각 줄에 적용
|
|
237
|
+
// Inserted lines background
|
|
261
238
|
const tobeLines = text.split('\n');
|
|
262
|
-
let
|
|
239
|
+
let currentTobeLineOffset = tobeCursor;
|
|
263
240
|
for(let i = 0; i < tobeLines.length; i++) {
|
|
264
|
-
//
|
|
265
|
-
const lineStart = tobeEditorView.state.doc.lineAt(
|
|
266
|
-
//
|
|
267
|
-
|
|
241
|
+
// Get line start/end from the *current* editor view's document
|
|
242
|
+
const lineStart = this.#tobeEditorView.state.doc.lineAt(currentTobeLineOffset).from;
|
|
243
|
+
// For the last segment of a multi-line insertion, the end is just current offset + segment length
|
|
244
|
+
// Otherwise, it's the end of the current line in the doc.
|
|
245
|
+
const lineEnd = i === tobeLines.length - 1 ? currentTobeLineOffset + tobeLines[i].length : this.#tobeEditorView.state.doc.lineAt(currentTobeLineOffset).to;
|
|
246
|
+
|
|
268
247
|
tobeBuilder.add(
|
|
269
|
-
lineStart, lineEnd,
|
|
248
|
+
lineStart, lineEnd,
|
|
270
249
|
Decoration.line({ class: "cm-inserted-line-bg" })
|
|
271
250
|
);
|
|
272
|
-
|
|
251
|
+
currentTobeLineOffset += tobeLines[i].length + 1; // Move to next line start
|
|
273
252
|
}
|
|
274
253
|
|
|
275
|
-
|
|
276
254
|
tobeCursor += len;
|
|
277
255
|
break;
|
|
278
256
|
|
|
279
|
-
case diff_match_patch.DIFF_DELETE:
|
|
280
|
-
// asis 쪽에 인라인 데코레이션 추가
|
|
257
|
+
case diff_match_patch.DIFF_DELETE:
|
|
281
258
|
asisBuilder.add(
|
|
282
259
|
asisCursor, asisCursor + len,
|
|
283
260
|
Decoration.mark({ class: "cm-deleted-inline" })
|
|
284
261
|
);
|
|
285
262
|
|
|
286
|
-
//
|
|
263
|
+
// Deleted lines background
|
|
287
264
|
const asisLines = text.split('\n');
|
|
288
265
|
let currentAsisLineOffset = asisCursor;
|
|
289
266
|
for(let i = 0; i < asisLines.length; i++) {
|
|
290
|
-
const lineStart = asisEditorView.state.doc.lineAt(currentAsisLineOffset).from;
|
|
291
|
-
const lineEnd = i === asisLines.length - 1 ? currentAsisLineOffset + asisLines[i].length : asisEditorView.state.doc.lineAt(currentAsisLineOffset).to;
|
|
267
|
+
const lineStart = this.#asisEditorView.state.doc.lineAt(currentAsisLineOffset).from;
|
|
268
|
+
const lineEnd = i === asisLines.length - 1 ? currentAsisLineOffset + asisLines[i].length : this.#asisEditorView.state.doc.lineAt(currentAsisLineOffset).to;
|
|
269
|
+
|
|
292
270
|
asisBuilder.add(
|
|
293
271
|
lineStart, lineEnd,
|
|
294
272
|
Decoration.line({ class: "cm-deleted-line-bg" })
|
|
@@ -299,14 +277,13 @@ export class IdeDiff extends HTMLElement {
|
|
|
299
277
|
asisCursor += len;
|
|
300
278
|
break;
|
|
301
279
|
|
|
302
|
-
case diff_match_patch.DIFF_EQUAL:
|
|
280
|
+
case diff_match_patch.DIFF_EQUAL:
|
|
303
281
|
asisCursor += len;
|
|
304
282
|
tobeCursor += len;
|
|
305
283
|
break;
|
|
306
284
|
}
|
|
307
285
|
}
|
|
308
286
|
|
|
309
|
-
// 에디터 뷰에 데코레이션 업데이트 요청 디스패치
|
|
310
287
|
this.#asisEditorView.dispatch({
|
|
311
288
|
effects: setAsisDecorationsEffect.of(asisBuilder.finish())
|
|
312
289
|
});
|
|
@@ -321,25 +298,15 @@ export class IdeDiff extends HTMLElement {
|
|
|
321
298
|
return;
|
|
322
299
|
}
|
|
323
300
|
|
|
324
|
-
// 언어 변경 (선택 사항, 필요 시 활성화)
|
|
325
301
|
let langExtension;
|
|
326
302
|
switch(language) {
|
|
327
303
|
case 'javascript':
|
|
328
304
|
langExtension = javascript();
|
|
329
305
|
break;
|
|
330
|
-
// case 'html':
|
|
331
|
-
// import { html } from "@codemirror/lang-html"; // 상단에 임포트 필요
|
|
332
|
-
// langExtension = html();
|
|
333
|
-
// break;
|
|
334
|
-
// case 'css':
|
|
335
|
-
// import { css } from "@codemirror/lang-css"; // 상단에 임포트 필요
|
|
336
|
-
// langExtension = css();
|
|
337
|
-
// break;
|
|
338
306
|
default:
|
|
339
307
|
langExtension = javascript();
|
|
340
308
|
}
|
|
341
309
|
|
|
342
|
-
// 언어 확장 업데이트
|
|
343
310
|
this.#asisEditorView.dispatch({
|
|
344
311
|
effects: this.#languageCompartment.reconfigure(langExtension)
|
|
345
312
|
});
|
package/package.json
CHANGED
|
@@ -24,12 +24,12 @@ import { autocompletion, completionKeymap } from "@codemirror/autocomplete";
|
|
|
24
24
|
// Diff 로직을 위해 diff-match-patch 사용
|
|
25
25
|
import { diff_match_patch } from 'diff-match-patch';
|
|
26
26
|
|
|
27
|
+
// --- 여기서부터 수정된 부분 ---
|
|
28
|
+
|
|
27
29
|
// Diff 데코레이션을 위한 StateField 정의 (asis 에디터용)
|
|
28
30
|
const asisDiffDecorations = StateField.define({
|
|
29
|
-
create() { return Decoration.none; },
|
|
31
|
+
create() { return Decoration.none; },
|
|
30
32
|
update(decorations, tr) {
|
|
31
|
-
// 트랜잭션에 포함된 Effects를 처리하여 데코레이션을 업데이트
|
|
32
|
-
// `#applyDiffDecorations` 함수에서 데코레이션 업데이트 요청을 보낼 때 사용
|
|
33
33
|
return tr.effects.reduce((currentDecos, effect) => {
|
|
34
34
|
if (effect.is(setAsisDecorationsEffect)) {
|
|
35
35
|
return effect.value;
|
|
@@ -37,7 +37,6 @@ const asisDiffDecorations = StateField.define({
|
|
|
37
37
|
return currentDecos;
|
|
38
38
|
}, decorations);
|
|
39
39
|
},
|
|
40
|
-
// 데코레이션을 뷰에 제공
|
|
41
40
|
provide: f => EditorView.decorations.from(f)
|
|
42
41
|
});
|
|
43
42
|
|
|
@@ -56,9 +55,11 @@ const tobeDiffDecorations = StateField.define({
|
|
|
56
55
|
});
|
|
57
56
|
|
|
58
57
|
// 데코레이션 업데이트를 위한 Effect (트랜잭션에 포함시켜 상태 변경 알림)
|
|
59
|
-
|
|
60
|
-
const
|
|
58
|
+
// ⭐️ 이 부분이 수정되었습니다: .define.effect() -> .defineEffect()
|
|
59
|
+
const setAsisDecorationsEffect = EditorState.defineEffect();
|
|
60
|
+
const setTobeDecorationsEffect = EditorState.defineEffect();
|
|
61
61
|
|
|
62
|
+
// --- 여기까지 수정된 부분 ---
|
|
62
63
|
|
|
63
64
|
export class IdeDiff extends HTMLElement {
|
|
64
65
|
#asisEditorView;
|
|
@@ -111,8 +112,6 @@ export class IdeDiff extends HTMLElement {
|
|
|
111
112
|
text-decoration: line-through;
|
|
112
113
|
font-weight: bold;
|
|
113
114
|
}
|
|
114
|
-
/* 선택적: 동일하지만 이동된 줄 강조 (복잡함) */
|
|
115
|
-
/* .cm-moved-line-bg {} */
|
|
116
115
|
</style>
|
|
117
116
|
|
|
118
117
|
<div class="wrapper">
|
|
@@ -136,7 +135,6 @@ export class IdeDiff extends HTMLElement {
|
|
|
136
135
|
return;
|
|
137
136
|
}
|
|
138
137
|
|
|
139
|
-
// CodeMirror 확장 기본 설정
|
|
140
138
|
const basicExtensions = [
|
|
141
139
|
lineNumbers(),
|
|
142
140
|
highlightSpecialChars(),
|
|
@@ -155,37 +153,35 @@ export class IdeDiff extends HTMLElement {
|
|
|
155
153
|
...lintKeymap,
|
|
156
154
|
...completionKeymap,
|
|
157
155
|
indentWithTab,
|
|
158
|
-
selectAll
|
|
156
|
+
selectAll
|
|
159
157
|
]),
|
|
160
158
|
syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
|
|
161
159
|
autocompletion(),
|
|
162
160
|
];
|
|
163
161
|
|
|
164
|
-
// asis 에디터 생성 (읽기 전용)
|
|
165
162
|
this.#asisEditorView = new EditorView({
|
|
166
163
|
state: EditorState.create({
|
|
167
164
|
doc: '',
|
|
168
165
|
extensions: [
|
|
169
166
|
basicExtensions,
|
|
170
|
-
javascript(),
|
|
171
|
-
EditorState.readOnly.of(true),
|
|
172
|
-
this.#languageCompartment.of(javascript()),
|
|
173
|
-
asisDiffDecorations
|
|
167
|
+
javascript(),
|
|
168
|
+
EditorState.readOnly.of(true),
|
|
169
|
+
this.#languageCompartment.of(javascript()),
|
|
170
|
+
asisDiffDecorations
|
|
174
171
|
]
|
|
175
172
|
}),
|
|
176
173
|
parent: this.#asisEditorEl
|
|
177
174
|
});
|
|
178
175
|
|
|
179
|
-
// tobe 에디터 생성 (읽기 전용, 필요 시 편집 가능하게 설정)
|
|
180
176
|
this.#tobeEditorView = new EditorView({
|
|
181
177
|
state: EditorState.create({
|
|
182
178
|
doc: '',
|
|
183
179
|
extensions: [
|
|
184
180
|
basicExtensions,
|
|
185
|
-
javascript(),
|
|
186
|
-
EditorState.readOnly.of(true),
|
|
187
|
-
this.#languageCompartment.of(javascript()),
|
|
188
|
-
tobeDiffDecorations
|
|
181
|
+
javascript(),
|
|
182
|
+
EditorState.readOnly.of(true),
|
|
183
|
+
this.#languageCompartment.of(javascript()),
|
|
184
|
+
tobeDiffDecorations
|
|
189
185
|
]
|
|
190
186
|
}),
|
|
191
187
|
parent: this.#tobeEditorEl
|
|
@@ -217,7 +213,6 @@ export class IdeDiff extends HTMLElement {
|
|
|
217
213
|
});
|
|
218
214
|
};
|
|
219
215
|
|
|
220
|
-
// ⭐️⭐️⭐️ Diff 데코레이션 적용 로직 구현 ⭐️⭐️⭐️
|
|
221
216
|
#applyDiffDecorations = (asisSrc, tobeSrc) => {
|
|
222
217
|
const dmp = new diff_match_patch();
|
|
223
218
|
const diffs = dmp.diff_main(asisSrc, tobeSrc);
|
|
@@ -226,69 +221,52 @@ export class IdeDiff extends HTMLElement {
|
|
|
226
221
|
const asisBuilder = new RangeSetBuilder();
|
|
227
222
|
const tobeBuilder = new RangeSetBuilder();
|
|
228
223
|
|
|
229
|
-
let asisCursor = 0;
|
|
230
|
-
let tobeCursor = 0;
|
|
231
|
-
|
|
232
|
-
// 줄 단위 데코레이션을 위해 줄 시작 위치를 추적
|
|
233
|
-
const asisLineStartMap = new Map();
|
|
234
|
-
const tobeLineStartMap = new Map();
|
|
235
|
-
|
|
236
|
-
// 각 텍스트에 대한 줄 시작 위치 미리 계산
|
|
237
|
-
let currentPos = 0;
|
|
238
|
-
for (const line of asisSrc.split('\n')) {
|
|
239
|
-
asisLineStartMap.set(currentPos, true);
|
|
240
|
-
currentPos += line.length + 1; // +1은 줄바꿈 문자 포함
|
|
241
|
-
}
|
|
242
|
-
currentPos = 0;
|
|
243
|
-
for (const line of tobeSrc.split('\n')) {
|
|
244
|
-
tobeLineStartMap.set(currentPos, true);
|
|
245
|
-
currentPos += line.length + 1;
|
|
246
|
-
}
|
|
224
|
+
let asisCursor = 0;
|
|
225
|
+
let tobeCursor = 0;
|
|
247
226
|
|
|
248
227
|
for (const [op, text] of diffs) {
|
|
249
228
|
const len = text.length;
|
|
250
229
|
|
|
251
230
|
switch (op) {
|
|
252
|
-
case diff_match_patch.DIFF_INSERT:
|
|
253
|
-
// tobe 쪽에 인라인 데코레이션 추가
|
|
231
|
+
case diff_match_patch.DIFF_INSERT:
|
|
254
232
|
tobeBuilder.add(
|
|
255
233
|
tobeCursor, tobeCursor + len,
|
|
256
234
|
Decoration.mark({ class: "cm-inserted-inline" })
|
|
257
235
|
);
|
|
258
236
|
|
|
259
|
-
//
|
|
260
|
-
// text가 여러 줄일 수 있으므로 각 줄에 적용
|
|
237
|
+
// Inserted lines background
|
|
261
238
|
const tobeLines = text.split('\n');
|
|
262
|
-
let
|
|
239
|
+
let currentTobeLineOffset = tobeCursor;
|
|
263
240
|
for(let i = 0; i < tobeLines.length; i++) {
|
|
264
|
-
//
|
|
265
|
-
const lineStart = tobeEditorView.state.doc.lineAt(
|
|
266
|
-
//
|
|
267
|
-
|
|
241
|
+
// Get line start/end from the *current* editor view's document
|
|
242
|
+
const lineStart = this.#tobeEditorView.state.doc.lineAt(currentTobeLineOffset).from;
|
|
243
|
+
// For the last segment of a multi-line insertion, the end is just current offset + segment length
|
|
244
|
+
// Otherwise, it's the end of the current line in the doc.
|
|
245
|
+
const lineEnd = i === tobeLines.length - 1 ? currentTobeLineOffset + tobeLines[i].length : this.#tobeEditorView.state.doc.lineAt(currentTobeLineOffset).to;
|
|
246
|
+
|
|
268
247
|
tobeBuilder.add(
|
|
269
|
-
lineStart, lineEnd,
|
|
248
|
+
lineStart, lineEnd,
|
|
270
249
|
Decoration.line({ class: "cm-inserted-line-bg" })
|
|
271
250
|
);
|
|
272
|
-
|
|
251
|
+
currentTobeLineOffset += tobeLines[i].length + 1; // Move to next line start
|
|
273
252
|
}
|
|
274
253
|
|
|
275
|
-
|
|
276
254
|
tobeCursor += len;
|
|
277
255
|
break;
|
|
278
256
|
|
|
279
|
-
case diff_match_patch.DIFF_DELETE:
|
|
280
|
-
// asis 쪽에 인라인 데코레이션 추가
|
|
257
|
+
case diff_match_patch.DIFF_DELETE:
|
|
281
258
|
asisBuilder.add(
|
|
282
259
|
asisCursor, asisCursor + len,
|
|
283
260
|
Decoration.mark({ class: "cm-deleted-inline" })
|
|
284
261
|
);
|
|
285
262
|
|
|
286
|
-
//
|
|
263
|
+
// Deleted lines background
|
|
287
264
|
const asisLines = text.split('\n');
|
|
288
265
|
let currentAsisLineOffset = asisCursor;
|
|
289
266
|
for(let i = 0; i < asisLines.length; i++) {
|
|
290
|
-
const lineStart = asisEditorView.state.doc.lineAt(currentAsisLineOffset).from;
|
|
291
|
-
const lineEnd = i === asisLines.length - 1 ? currentAsisLineOffset + asisLines[i].length : asisEditorView.state.doc.lineAt(currentAsisLineOffset).to;
|
|
267
|
+
const lineStart = this.#asisEditorView.state.doc.lineAt(currentAsisLineOffset).from;
|
|
268
|
+
const lineEnd = i === asisLines.length - 1 ? currentAsisLineOffset + asisLines[i].length : this.#asisEditorView.state.doc.lineAt(currentAsisLineOffset).to;
|
|
269
|
+
|
|
292
270
|
asisBuilder.add(
|
|
293
271
|
lineStart, lineEnd,
|
|
294
272
|
Decoration.line({ class: "cm-deleted-line-bg" })
|
|
@@ -299,14 +277,13 @@ export class IdeDiff extends HTMLElement {
|
|
|
299
277
|
asisCursor += len;
|
|
300
278
|
break;
|
|
301
279
|
|
|
302
|
-
case diff_match_patch.DIFF_EQUAL:
|
|
280
|
+
case diff_match_patch.DIFF_EQUAL:
|
|
303
281
|
asisCursor += len;
|
|
304
282
|
tobeCursor += len;
|
|
305
283
|
break;
|
|
306
284
|
}
|
|
307
285
|
}
|
|
308
286
|
|
|
309
|
-
// 에디터 뷰에 데코레이션 업데이트 요청 디스패치
|
|
310
287
|
this.#asisEditorView.dispatch({
|
|
311
288
|
effects: setAsisDecorationsEffect.of(asisBuilder.finish())
|
|
312
289
|
});
|
|
@@ -321,25 +298,15 @@ export class IdeDiff extends HTMLElement {
|
|
|
321
298
|
return;
|
|
322
299
|
}
|
|
323
300
|
|
|
324
|
-
// 언어 변경 (선택 사항, 필요 시 활성화)
|
|
325
301
|
let langExtension;
|
|
326
302
|
switch(language) {
|
|
327
303
|
case 'javascript':
|
|
328
304
|
langExtension = javascript();
|
|
329
305
|
break;
|
|
330
|
-
// case 'html':
|
|
331
|
-
// import { html } from "@codemirror/lang-html"; // 상단에 임포트 필요
|
|
332
|
-
// langExtension = html();
|
|
333
|
-
// break;
|
|
334
|
-
// case 'css':
|
|
335
|
-
// import { css } from "@codemirror/lang-css"; // 상단에 임포트 필요
|
|
336
|
-
// langExtension = css();
|
|
337
|
-
// break;
|
|
338
306
|
default:
|
|
339
307
|
langExtension = javascript();
|
|
340
308
|
}
|
|
341
309
|
|
|
342
|
-
// 언어 확장 업데이트
|
|
343
310
|
this.#asisEditorView.dispatch({
|
|
344
311
|
effects: this.#languageCompartment.reconfigure(langExtension)
|
|
345
312
|
});
|