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.
- package/dist/bundle.cjs.js +55 -47
- package/dist/bundle.esm.js +55 -47
- package/dist/components/ideDiff.js +55 -47
- package/package.json +1 -1
- package/src/components/ideDiff.js +55 -47
package/dist/bundle.cjs.js
CHANGED
|
@@ -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
|
-
|
|
234918
|
-
|
|
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
|
|
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
|
-
|
|
235069
|
+
// ASIS는 읽기 전용으로 유지 (원본 소스) - 필요에 따라 편집 가능하도록 변경 가능
|
|
235070
|
+
EditorState.readOnly.of(false), // ASIS를 편집 가능하게 변경
|
|
235061
235071
|
asisDiffDecorations,
|
|
235062
|
-
asisButtonDecorations,
|
|
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,
|
|
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
|
|
235176
|
-
// TOBE의 해당 Diff가 끝나는 지점에 버튼을 붙이는 것이 자연스럽습니다.
|
|
235177
|
-
// tobeRangeStart는 Diff 청크의 시작 오프셋입니다.
|
|
235178
|
-
// 버튼을 Line Decoration과 같은 위치에 추가하되, 별도의 builder 사용
|
|
235186
|
+
// ⭐️ TOBE (AI 추천) 에디터에 버튼 추가: TOBE의 추가 내용을 ASIS (현재 소스)에 '적용'
|
|
235179
235187
|
tobeButtonBuilder.add(
|
|
235180
|
-
tobeRangeStart,
|
|
235188
|
+
tobeRangeStart,
|
|
235181
235189
|
tobeRangeStart,
|
|
235182
235190
|
Decoration.widget({
|
|
235183
235191
|
widget: new MergeButtonWidget(
|
|
235184
|
-
false, // 이 버튼은 TOBE 에디터에 붙는 버튼
|
|
235185
|
-
|
|
235186
|
-
currentInstance.#asisEditorView, // 대상 에디터는 ASIS
|
|
235187
|
-
{ from: asisRangeStart, to: asisRangeStart +
|
|
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
|
|
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 에디터에 버튼 추가:
|
|
235213
|
+
// ⭐️ ASIS (현재 소스) 에디터에 버튼 추가: AI의 삭제를 '삭제' (ASIS에서 해당 내용을 제거)
|
|
235206
235214
|
asisButtonBuilder.add(
|
|
235207
|
-
asisRangeStart,
|
|
235215
|
+
asisRangeStart,
|
|
235208
235216
|
asisRangeStart,
|
|
235209
235217
|
Decoration.widget({
|
|
235210
235218
|
widget: new MergeButtonWidget(
|
|
235211
|
-
true, // 이 버튼은 ASIS 에디터에 붙는 버튼
|
|
235212
|
-
|
|
235213
|
-
currentInstance.#
|
|
235214
|
-
{ from:
|
|
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)
|
|
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)
|
|
235260
|
+
setTobeButtonDecorationsEffect.of(tobeButtonDecorations)
|
|
235253
235261
|
]
|
|
235254
235262
|
});
|
|
235255
235263
|
};
|
package/dist/bundle.esm.js
CHANGED
|
@@ -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
|
-
|
|
234914
|
-
|
|
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
|
|
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
|
-
|
|
235065
|
+
// ASIS는 읽기 전용으로 유지 (원본 소스) - 필요에 따라 편집 가능하도록 변경 가능
|
|
235066
|
+
EditorState.readOnly.of(false), // ASIS를 편집 가능하게 변경
|
|
235057
235067
|
asisDiffDecorations,
|
|
235058
|
-
asisButtonDecorations,
|
|
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,
|
|
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
|
|
235172
|
-
// TOBE의 해당 Diff가 끝나는 지점에 버튼을 붙이는 것이 자연스럽습니다.
|
|
235173
|
-
// tobeRangeStart는 Diff 청크의 시작 오프셋입니다.
|
|
235174
|
-
// 버튼을 Line Decoration과 같은 위치에 추가하되, 별도의 builder 사용
|
|
235182
|
+
// ⭐️ TOBE (AI 추천) 에디터에 버튼 추가: TOBE의 추가 내용을 ASIS (현재 소스)에 '적용'
|
|
235175
235183
|
tobeButtonBuilder.add(
|
|
235176
|
-
tobeRangeStart,
|
|
235184
|
+
tobeRangeStart,
|
|
235177
235185
|
tobeRangeStart,
|
|
235178
235186
|
Decoration.widget({
|
|
235179
235187
|
widget: new MergeButtonWidget(
|
|
235180
|
-
false, // 이 버튼은 TOBE 에디터에 붙는 버튼
|
|
235181
|
-
|
|
235182
|
-
currentInstance.#asisEditorView, // 대상 에디터는 ASIS
|
|
235183
|
-
{ from: asisRangeStart, to: asisRangeStart +
|
|
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
|
|
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 에디터에 버튼 추가:
|
|
235209
|
+
// ⭐️ ASIS (현재 소스) 에디터에 버튼 추가: AI의 삭제를 '삭제' (ASIS에서 해당 내용을 제거)
|
|
235202
235210
|
asisButtonBuilder.add(
|
|
235203
|
-
asisRangeStart,
|
|
235211
|
+
asisRangeStart,
|
|
235204
235212
|
asisRangeStart,
|
|
235205
235213
|
Decoration.widget({
|
|
235206
235214
|
widget: new MergeButtonWidget(
|
|
235207
|
-
true, // 이 버튼은 ASIS 에디터에 붙는 버튼
|
|
235208
|
-
|
|
235209
|
-
currentInstance.#
|
|
235210
|
-
{ from:
|
|
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)
|
|
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)
|
|
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
|
-
|
|
114
|
-
|
|
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
|
|
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
|
-
|
|
265
|
+
// ASIS는 읽기 전용으로 유지 (원본 소스) - 필요에 따라 편집 가능하도록 변경 가능
|
|
266
|
+
EditorState.readOnly.of(false), // ASIS를 편집 가능하게 변경
|
|
257
267
|
asisDiffDecorations,
|
|
258
|
-
asisButtonDecorations,
|
|
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,
|
|
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
|
|
372
|
-
// TOBE의 해당 Diff가 끝나는 지점에 버튼을 붙이는 것이 자연스럽습니다.
|
|
373
|
-
// tobeRangeStart는 Diff 청크의 시작 오프셋입니다.
|
|
374
|
-
// 버튼을 Line Decoration과 같은 위치에 추가하되, 별도의 builder 사용
|
|
382
|
+
// ⭐️ TOBE (AI 추천) 에디터에 버튼 추가: TOBE의 추가 내용을 ASIS (현재 소스)에 '적용'
|
|
375
383
|
tobeButtonBuilder.add(
|
|
376
|
-
tobeRangeStart,
|
|
384
|
+
tobeRangeStart,
|
|
377
385
|
tobeRangeStart,
|
|
378
386
|
Decoration.widget({
|
|
379
387
|
widget: new MergeButtonWidget(
|
|
380
|
-
false, // 이 버튼은 TOBE 에디터에 붙는 버튼
|
|
381
|
-
|
|
382
|
-
currentInstance.#asisEditorView, // 대상 에디터는 ASIS
|
|
383
|
-
{ from: asisRangeStart, to: asisRangeStart +
|
|
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
|
|
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 에디터에 버튼 추가:
|
|
409
|
+
// ⭐️ ASIS (현재 소스) 에디터에 버튼 추가: AI의 삭제를 '삭제' (ASIS에서 해당 내용을 제거)
|
|
402
410
|
asisButtonBuilder.add(
|
|
403
|
-
asisRangeStart,
|
|
411
|
+
asisRangeStart,
|
|
404
412
|
asisRangeStart,
|
|
405
413
|
Decoration.widget({
|
|
406
414
|
widget: new MergeButtonWidget(
|
|
407
|
-
true, // 이 버튼은 ASIS 에디터에 붙는 버튼
|
|
408
|
-
|
|
409
|
-
currentInstance.#
|
|
410
|
-
{ from:
|
|
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)
|
|
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)
|
|
456
|
+
setTobeButtonDecorationsEffect.of(tobeButtonDecorations)
|
|
449
457
|
]
|
|
450
458
|
});
|
|
451
459
|
};
|
package/package.json
CHANGED
|
@@ -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
|
-
|
|
114
|
-
|
|
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
|
|
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
|
-
|
|
265
|
+
// ASIS는 읽기 전용으로 유지 (원본 소스) - 필요에 따라 편집 가능하도록 변경 가능
|
|
266
|
+
EditorState.readOnly.of(false), // ASIS를 편집 가능하게 변경
|
|
257
267
|
asisDiffDecorations,
|
|
258
|
-
asisButtonDecorations,
|
|
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,
|
|
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
|
|
372
|
-
// TOBE의 해당 Diff가 끝나는 지점에 버튼을 붙이는 것이 자연스럽습니다.
|
|
373
|
-
// tobeRangeStart는 Diff 청크의 시작 오프셋입니다.
|
|
374
|
-
// 버튼을 Line Decoration과 같은 위치에 추가하되, 별도의 builder 사용
|
|
382
|
+
// ⭐️ TOBE (AI 추천) 에디터에 버튼 추가: TOBE의 추가 내용을 ASIS (현재 소스)에 '적용'
|
|
375
383
|
tobeButtonBuilder.add(
|
|
376
|
-
tobeRangeStart,
|
|
384
|
+
tobeRangeStart,
|
|
377
385
|
tobeRangeStart,
|
|
378
386
|
Decoration.widget({
|
|
379
387
|
widget: new MergeButtonWidget(
|
|
380
|
-
false, // 이 버튼은 TOBE 에디터에 붙는 버튼
|
|
381
|
-
|
|
382
|
-
currentInstance.#asisEditorView, // 대상 에디터는 ASIS
|
|
383
|
-
{ from: asisRangeStart, to: asisRangeStart +
|
|
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
|
|
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 에디터에 버튼 추가:
|
|
409
|
+
// ⭐️ ASIS (현재 소스) 에디터에 버튼 추가: AI의 삭제를 '삭제' (ASIS에서 해당 내용을 제거)
|
|
402
410
|
asisButtonBuilder.add(
|
|
403
|
-
asisRangeStart,
|
|
411
|
+
asisRangeStart,
|
|
404
412
|
asisRangeStart,
|
|
405
413
|
Decoration.widget({
|
|
406
414
|
widget: new MergeButtonWidget(
|
|
407
|
-
true, // 이 버튼은 ASIS 에디터에 붙는 버튼
|
|
408
|
-
|
|
409
|
-
currentInstance.#
|
|
410
|
-
{ from:
|
|
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)
|
|
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)
|
|
456
|
+
setTobeButtonDecorationsEffect.of(tobeButtonDecorations)
|
|
449
457
|
]
|
|
450
458
|
});
|
|
451
459
|
};
|