ide-assi 0.402.0 → 0.403.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.
@@ -217623,6 +217623,31 @@ function maxLineNumber(lines) {
217623
217623
  last = last * 10 + 9;
217624
217624
  return last;
217625
217625
  }
217626
+ const activeLineGutterMarker = /*@__PURE__*/new class extends GutterMarker {
217627
+ constructor() {
217628
+ super(...arguments);
217629
+ this.elementClass = "cm-activeLineGutter";
217630
+ }
217631
+ };
217632
+ const activeLineGutterHighlighter = /*@__PURE__*/gutterLineClass.compute(["selection"], state => {
217633
+ let marks = [], last = -1;
217634
+ for (let range of state.selection.ranges) {
217635
+ let linePos = state.doc.lineAt(range.head).from;
217636
+ if (linePos > last) {
217637
+ last = linePos;
217638
+ marks.push(activeLineGutterMarker.range(linePos));
217639
+ }
217640
+ }
217641
+ return RangeSet.of(marks);
217642
+ });
217643
+ /**
217644
+ Returns an extension that adds a `cm-activeLineGutter` class to
217645
+ all gutter elements on the [active
217646
+ line](https://codemirror.net/6/docs/ref/#view.highlightActiveLine).
217647
+ */
217648
+ function highlightActiveLineGutter() {
217649
+ return activeLineGutterHighlighter;
217650
+ }
217626
217651
 
217627
217652
  /**
217628
217653
  The default maximum length of a `TreeBuffer` node.
@@ -221387,50 +221412,6 @@ function continuedIndent({ except, units = 1 } = {}) {
221387
221412
  return context.baseIndent + (matchExcept ? 0 : units * context.unit);
221388
221413
  };
221389
221414
  }
221390
- const DontIndentBeyond = 200;
221391
- /**
221392
- Enables reindentation on input. When a language defines an
221393
- `indentOnInput` field in its [language
221394
- data](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt), which must hold a regular
221395
- expression, the line at the cursor will be reindented whenever new
221396
- text is typed and the input from the start of the line up to the
221397
- cursor matches that regexp.
221398
-
221399
- To avoid unneccesary reindents, it is recommended to start the
221400
- regexp with `^` (usually followed by `\s*`), and end it with `$`.
221401
- For example, `/^\s*\}$/` will reindent when a closing brace is
221402
- added at the start of a line.
221403
- */
221404
- function indentOnInput() {
221405
- return EditorState.transactionFilter.of(tr => {
221406
- if (!tr.docChanged || !tr.isUserEvent("input.type") && !tr.isUserEvent("input.complete"))
221407
- return tr;
221408
- let rules = tr.startState.languageDataAt("indentOnInput", tr.startState.selection.main.head);
221409
- if (!rules.length)
221410
- return tr;
221411
- let doc = tr.newDoc, { head } = tr.newSelection.main, line = doc.lineAt(head);
221412
- if (head > line.from + DontIndentBeyond)
221413
- return tr;
221414
- let lineStart = doc.sliceString(line.from, head);
221415
- if (!rules.some(r => r.test(lineStart)))
221416
- return tr;
221417
- let { state } = tr, last = -1, changes = [];
221418
- for (let { head } of state.selection.ranges) {
221419
- let line = state.doc.lineAt(head);
221420
- if (line.from == last)
221421
- continue;
221422
- last = line.from;
221423
- let indent = getIndentation(state, line.from);
221424
- if (indent == null)
221425
- continue;
221426
- let cur = /^\s*/.exec(line.text)[0];
221427
- let norm = indentString(state, indent);
221428
- if (cur != norm)
221429
- changes.push({ from: line.from, to: line.from + cur.length, insert: norm });
221430
- }
221431
- return changes.length ? [tr, { changes, sequential: true }] : tr;
221432
- });
221433
- }
221434
221415
  /**
221435
221416
  This node prop is used to associate folding information with
221436
221417
  syntax node types. Given a syntax node, it should check whether
@@ -221519,9 +221500,7 @@ function syntaxHighlighting(highlighter, options) {
221519
221500
  ext.push(EditorView.styleModule.of(highlighter.module));
221520
221501
  themeType = highlighter.themeType;
221521
221502
  }
221522
- if (options === null || options === void 0 ? void 0 : options.fallback)
221523
- ext.push(fallbackHighlighter.of(highlighter));
221524
- else if (themeType)
221503
+ if (themeType)
221525
221504
  ext.push(highlighterFacet.computeN([EditorView.darkTheme], state => {
221526
221505
  return state.facet(EditorView.darkTheme) == (themeType == "dark") ? [highlighter] : [];
221527
221506
  }));
@@ -234776,35 +234755,45 @@ function requireDiffMatchPatch () {
234776
234755
 
234777
234756
  var diffMatchPatchExports = requireDiffMatchPatch();
234778
234757
 
234779
- // Diff 데코레이션을 위한 StateField 정의 (변동 없음)
234758
+ // --- Diff 데코레이션을 위한 StateEffect 정의 (수정: DecorationSet 타입 명시) ---
234759
+ const setAsisDecorationsEffect = StateEffect.define();
234760
+ const setTobeDecorationsEffect = StateEffect.define();
234761
+
234762
+ // --- Diff 데코레이션을 위한 StateField 정의 ---
234780
234763
  const asisDiffDecorations = StateField.define({
234781
- create() { return Decoration.none; },
234764
+ create() {
234765
+ return Decoration.none; // 초기 상태: 데코레이션 없음
234766
+ },
234782
234767
  update(decorations, tr) {
234783
- return tr.effects.reduce((currentDecos, effect) => {
234768
+ // 트랜잭션의 변화를 데코레이션에 매핑하여 위치가 변경되어도 데코레이션이 유지되도록 함
234769
+ decorations = decorations.map(tr.changes);
234770
+ // setAsisDecorationsEffect가 있다면 해당 효과의 값을 적용
234771
+ for (let effect of tr.effects) {
234784
234772
  if (effect.is(setAsisDecorationsEffect)) {
234785
- return effect.value;
234773
+ return effect.value; // 새로운 DecorationSet으로 교체
234786
234774
  }
234787
- return currentDecos;
234788
- }, decorations);
234775
+ }
234776
+ return decorations; // 효과가 없으면 기존 데코레이션 반환
234789
234777
  },
234790
- provide: f => EditorView.decorations.from(f)
234778
+ provide: f => EditorView.decorations.from(f) // 이 필드가 제공하는 데코레이션을 EditorView.decorations 확장으로 등록
234791
234779
  });
234792
234780
 
234793
234781
  const tobeDiffDecorations = StateField.define({
234794
- create() { return Decoration.none; },
234782
+ create() {
234783
+ return Decoration.none; // 초기 상태: 데코레이션 없음
234784
+ },
234795
234785
  update(decorations, tr) {
234796
- return tr.effects.reduce((currentDecos, effect) => {
234786
+ decorations = decorations.map(tr.changes);
234787
+ for (let effect of tr.effects) {
234797
234788
  if (effect.is(setTobeDecorationsEffect)) {
234798
- return effect.value;
234789
+ return effect.value; // 새로운 DecorationSet으로 교체
234799
234790
  }
234800
- return currentDecos;
234801
- }, decorations);
234791
+ }
234792
+ return decorations;
234802
234793
  },
234803
234794
  provide: f => EditorView.decorations.from(f)
234804
234795
  });
234805
234796
 
234806
- const setAsisDecorationsEffect = StateEffect.define();
234807
- const setTobeDecorationsEffect = StateEffect.define();
234808
234797
 
234809
234798
  class IdeDiff extends HTMLElement {
234810
234799
 
@@ -234828,9 +234817,13 @@ class IdeDiff extends HTMLElement {
234828
234817
  connectedCallback() {
234829
234818
  this.shadowRoot.innerHTML = `
234830
234819
  <style>
234831
- /* ninegrid CSS 및 필요한 기본 스타일 (변동 없음) */
234820
+ /* ninegrid CSS 및 필요한 기본 스타일 */
234832
234821
  @import "https://cdn.jsdelivr.net/npm/ninegrid@${ninegrid.version}/dist/css/ideDiff.css";
234833
234822
  ${ninegrid.getCustomPath(this, "ideDiff.css")}
234823
+
234824
+ /* Diff 데코레이션 CSS 직접 추가 (없으면 ideDiff.css에 추가) */
234825
+ .cm-inserted-line-bg { background-color: #e6ffed; border-left: 3px solid #66bb6a; }
234826
+ .cm-deleted-line-bg { background-color: #ffebe9; border-left: 3px solid #ef5350; }
234834
234827
  </style>
234835
234828
 
234836
234829
  <div class="wrapper">
@@ -234845,6 +234838,22 @@ class IdeDiff extends HTMLElement {
234845
234838
  });
234846
234839
  }
234847
234840
 
234841
+ disconnectedCallback() {
234842
+ // 컴포넌트 해제 시 스크롤 리스너 제거
234843
+ if (this._asisScrollHandler) {
234844
+ this.#asisEditorView.scrollDOM.removeEventListener('scroll', this._asisScrollHandler);
234845
+ this.#tobeEditorView.scrollDOM.removeEventListener('scroll', this._tobeScrollHandler);
234846
+ this._asisScrollHandler = null;
234847
+ this._tobeScrollHandler = null;
234848
+ }
234849
+ if (this.#asisEditorView) {
234850
+ this.#asisEditorView.destroy();
234851
+ }
234852
+ if (this.#tobeEditorView) {
234853
+ this.#tobeEditorView.destroy();
234854
+ }
234855
+ }
234856
+
234848
234857
  #initCodeMirror = () => {
234849
234858
  this.#asisEditorEl = this.shadowRoot.querySelector('.panel.asis');
234850
234859
  this.#tobeEditorEl = this.shadowRoot.querySelector('.panel.tobe');
@@ -234861,9 +234870,10 @@ class IdeDiff extends HTMLElement {
234861
234870
  drawSelection(),
234862
234871
  dropCursor(),
234863
234872
  EditorState.allowMultipleSelections.of(true),
234864
- indentOnInput(),
234873
+ indentOnInput(), // 함수 호출
234865
234874
  bracketMatching(),
234866
234875
  highlightActiveLine(),
234876
+ highlightActiveLineGutter(),
234867
234877
  highlightSelectionMatches(),
234868
234878
  keymap.of([
234869
234879
  ...defaultKeymap,
@@ -234871,11 +234881,11 @@ class IdeDiff extends HTMLElement {
234871
234881
  ...historyKeymap,
234872
234882
  ...lintKeymap,
234873
234883
  ...completionKeymap,
234874
- indentWithTab,
234875
- selectAll
234884
+ indentWithTab(), // 함수 호출
234885
+ selectAll() // 함수 호출
234876
234886
  ]),
234877
- syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
234878
- autocompletion(),
234887
+ syntaxHighlighting(defaultHighlightStyle), // { fallback: true } 제거
234888
+ autocompletion(), // 함수 호출
234879
234889
  ];
234880
234890
 
234881
234891
  // ASIS 에디터 뷰 초기화
@@ -234884,11 +234894,9 @@ class IdeDiff extends HTMLElement {
234884
234894
  doc: '',
234885
234895
  extensions: [
234886
234896
  basicExtensions,
234887
- javascript(),
234897
+ this.#languageCompartment.of(javascript()), // 초기 언어 설정
234888
234898
  EditorState.readOnly.of(true),
234889
- this.#languageCompartment.of(javascript()),
234890
- asisDiffDecorations,
234891
- // ⭐️ updateListener는 유지: 뷰가 DOM에 완전히 렌더링될 때까지 기다림
234899
+ asisDiffDecorations, // ASIS Diff 데코레이션 필드
234892
234900
  EditorView.updateListener.of((update) => {
234893
234901
  if (update.view.contentDOM.firstChild && !update.view._initialAsisContentLoaded) {
234894
234902
  update.view._initialAsisContentLoaded = true;
@@ -234906,11 +234914,9 @@ class IdeDiff extends HTMLElement {
234906
234914
  doc: '',
234907
234915
  extensions: [
234908
234916
  basicExtensions,
234909
- javascript(),
234917
+ this.#languageCompartment.of(javascript()), // 초기 언어 설정
234910
234918
  EditorState.readOnly.of(true),
234911
- this.#languageCompartment.of(javascript()),
234912
- tobeDiffDecorations,
234913
- // ⭐️ updateListener는 유지: 뷰가 DOM에 완전히 렌더링될 때까지 기다림
234919
+ tobeDiffDecorations, // TOBE Diff 데코레이션 필드
234914
234920
  EditorView.updateListener.of((update) => {
234915
234921
  if (update.view.contentDOM.firstChild && !update.view._initialTobeContentLoaded) {
234916
234922
  update.view._initialTobeContentLoaded = true;
@@ -234960,71 +234966,49 @@ class IdeDiff extends HTMLElement {
234960
234966
  this.#tobeEditorView.scrollDOM.addEventListener('scroll', this._tobeScrollHandler);
234961
234967
  };
234962
234968
 
234963
- // IdeDiff 클래스 내부
234969
+ // Diff 데코레이션 계산 및 반환 함수
234964
234970
  #applyDiffDecorations = (asisSrc, tobeSrc) => {
234965
234971
  const dmp = new diffMatchPatchExports.diff_match_patch();
234966
234972
  const diffs = dmp.diff_main(asisSrc, tobeSrc);
234967
234973
  dmp.diff_cleanupSemantic(diffs);
234968
234974
 
234969
- const asisLineDecos = [];
234970
- const tobeLineDecos = [];
234975
+ const asisLineBuilder = new RangeSetBuilder();
234976
+ const tobeLineBuilder = new RangeSetBuilder();
234971
234977
 
234972
- let asisCursor = 0;
234973
- let tobeCursor = 0;
234978
+ let asisCursor = 0; // ASIS 텍스트에서의 현재 커서 위치 (문자 오프셋)
234979
+ let tobeCursor = 0; // TOBE 텍스트에서의 현재 커서 위치 (문자 오프셋)
234974
234980
 
234975
- // 중요: 새로운 문서 내용을 기반으로 임시 Doc 객체를 생성합니다.
234976
- // Doc 객체를 사용하여 lineAt()을 호출합니다.
234977
- const asisDoc = Text.of(asisSrc.split('\n'));
234978
- const tobeDoc = Text.of(tobeSrc.split('\n'));
234981
+ // Decoration 인스턴스 미리 생성
234982
+ const insertedLineDeco = Decoration.line({ class: "cm-inserted-line-bg" });
234983
+ const deletedLineDeco = Decoration.line({ class: "cm-deleted-line-bg" });
234979
234984
 
234980
234985
  for (const [op, text] of diffs) {
234981
- const len = text.length;
234986
+ const len = text.length; // 현재 Diff 청크의 텍스트 길이
234987
+ const linesInChunk = text.split('\n');
234982
234988
 
234983
234989
  switch (op) {
234984
- case diffMatchPatchExports.diff_match_patch.DIFF_INSERT: // Added text
234985
- let currentTobeLineOffset = tobeCursor;
234986
- const tobeLines = text.split('\n');
234987
- for (let i = 0; i < tobeLines.length; i++) {
234988
- // 줄의 시작 오프셋이 tobeDoc의 길이를 넘지 않는지 확인
234989
- if (currentTobeLineOffset < tobeDoc.length) {
234990
- const line = tobeDoc.lineAt(currentTobeLineOffset);
234991
- tobeLineDecos.push({
234992
- from: line.from,
234993
- to: line.to,
234994
- deco: Decoration.line({ class: "cm-inserted-line-bg" })
234995
- });
234996
- }
234997
- // 다음 줄의 시작 오프셋 계산 (개행 문자 고려)
234998
- currentTobeLineOffset += tobeLines[i].length + (i < tobeLines.length - 1 ? 1 : 0);
234999
- // 마지막 줄이 비어 있고 개행으로 끝나지 않으면 루프 종료 (lineAt 오류 방지)
235000
- if (i === tobeLines.length - 1 && tobeLines[i].length === 0 && text.endsWith('\n') === false) {
234990
+ case diffMatchPatchExports.diff_match_patch.DIFF_INSERT: // Added text (TOBE에만 존재)
234991
+ for (let i = 0; i < linesInChunk.length; i++) {
234992
+ // 마지막 줄이 비어있고 해당 청크가 개행으로 끝나지 않으면 스킵
234993
+ if (i === linesInChunk.length - 1 && linesInChunk[i] === '' && !text.endsWith('\n')) {
234994
+ tobeCursor += len; // tobeCursor만 해당 청크 길이만큼 증가
235001
234995
  break;
235002
234996
  }
234997
+ // Decoration.line은 줄의 시작 위치에만 추가하면 CodeMirror가 해당 줄 전체에 적용합니다.
234998
+ tobeLineBuilder.add(tobeCursor, tobeCursor, insertedLineDeco);
234999
+ tobeCursor += linesInChunk[i].length + (i < linesInChunk.length - 1 ? 1 : 0);
235003
235000
  }
235004
- tobeCursor += len;
235005
235001
  break;
235006
235002
 
235007
- case diffMatchPatchExports.diff_match_patch.DIFF_DELETE: // Deleted text
235008
- let currentAsisLineOffset = asisCursor;
235009
- const asisLines = text.split('\n');
235010
- for (let i = 0; i < asisLines.length; i++) {
235011
- // 줄의 시작 오프셋이 asisDoc의 길이를 넘지 않는지 확인
235012
- if (currentAsisLineOffset < asisDoc.length) {
235013
- const line = asisDoc.lineAt(currentAsisLineOffset);
235014
- asisLineDecos.push({
235015
- from: line.from,
235016
- to: line.to,
235017
- deco: Decoration.line({ class: "cm-deleted-line-bg" })
235018
- });
235019
- }
235020
- // 다음 줄의 시작 오프셋 계산 (개행 문자 고려)
235021
- currentAsisLineOffset += asisLines[i].length + (i < asisLines.length - 1 ? 1 : 0);
235022
- // 마지막 줄이 비어 있고 개행으로 끝나지 않으면 루프 종료 (lineAt 오류 방지)
235023
- if (i === asisLines.length - 1 && asisLines[i].length === 0 && text.endsWith('\n') === false) {
235003
+ case diffMatchPatchExports.diff_match_patch.DIFF_DELETE: // Deleted text (ASIS에만 존재)
235004
+ for (let i = 0; i < linesInChunk.length; i++) {
235005
+ if (i === linesInChunk.length - 1 && linesInChunk[i] === '' && !text.endsWith('\n')) {
235006
+ asisCursor += len;
235024
235007
  break;
235025
235008
  }
235009
+ asisLineBuilder.add(asisCursor, asisCursor, deletedLineDeco);
235010
+ asisCursor += linesInChunk[i].length + (i < linesInChunk.length - 1 ? 1 : 0);
235026
235011
  }
235027
- asisCursor += len;
235028
235012
  break;
235029
235013
 
235030
235014
  case diffMatchPatchExports.diff_match_patch.DIFF_EQUAL: // Unchanged text
@@ -235034,26 +235018,9 @@ class IdeDiff extends HTMLElement {
235034
235018
  }
235035
235019
  }
235036
235020
 
235037
- // 데코레이션 중복 및 겹침 방지를 위해 정렬
235038
- asisLineDecos.sort((a, b) => a.from - b.from);
235039
- tobeLineDecos.sort((a, b) => a.from - b.from);
235040
-
235041
- // 라인 데코레이션 빌더 생성
235042
- const asisLineBuilder = new RangeSetBuilder();
235043
- for (const { from, to, deco } of asisLineDecos) {
235044
- asisLineBuilder.add(from, to, deco);
235045
- }
235046
- const finalAsisDecorations = asisLineBuilder.finish(); // ⭐️ .update({ add: ... }) 부분 제거
235047
-
235048
- const tobeLineBuilder = new RangeSetBuilder();
235049
- for (const { from, to, deco } of tobeLineDecos) {
235050
- tobeLineBuilder.add(from, to, deco);
235051
- }
235052
- const finalTobeDecorations = tobeLineBuilder.finish(); // ⭐️ .update({ add: ... }) 부분 제거
235053
-
235054
235021
  return {
235055
- asisEffect: setAsisDecorationsEffect.of(finalAsisDecorations),
235056
- tobeEffect: setTobeDecorationsEffect.of(finalTobeDecorations)
235022
+ asisDecorations: asisLineBuilder.finish(),
235023
+ tobeDecorations: tobeLineBuilder.finish()
235057
235024
  };
235058
235025
  };
235059
235026
 
@@ -235070,16 +235037,17 @@ class IdeDiff extends HTMLElement {
235070
235037
  case 'javascript':
235071
235038
  langExtension = javascript();
235072
235039
  break;
235040
+ // case 'java':
235041
+ // langExtension = java();
235042
+ // break;
235043
+ // case 'xml':
235044
+ // langExtension = xml();
235045
+ // break;
235073
235046
  default:
235074
- langExtension = javascript();
235047
+ langExtension = javascript(); // 기본값
235075
235048
  }
235076
235049
 
235077
- // 데코레이션 효과는 미리 계산해 둡니다.
235078
- const { asisEffect, tobeEffect } = this.#applyDiffDecorations(src1, src2);
235079
-
235080
235050
  // 1단계: 텍스트 내용 변경과 언어 확장을 먼저 디스패치합니다.
235081
- // 'to' 값을 현재 문서 길이 전체로 지정하여 정확한 교체를 보장합니다.
235082
-
235083
235051
  this.#asisEditorView.dispatch({
235084
235052
  changes: { from: 0, to: this.#asisEditorView.state.doc.length, insert: src1 },
235085
235053
  effects: [
@@ -235094,27 +235062,19 @@ class IdeDiff extends HTMLElement {
235094
235062
  ]
235095
235063
  });
235096
235064
 
235097
- console.log(asisEffect, tobeEffect);
235098
-
235099
- // ⭐️ 2단계: 텍스트 및 언어 변경이 완전히 적용되고 뷰가 안정화될 시간을 줍니다.
235065
+ // 2단계: 텍스트 및 언어 변경이 완전히 적용되고 뷰가 안정화될 시간을 줍니다.
235100
235066
  // 다음 프레임에서 데코레이션 효과만 별도로 디스패치합니다.
235101
235067
  requestAnimationFrame(() => {
235068
+ const { asisDecorations, tobeDecorations } = this.#applyDiffDecorations(src1, src2);
235069
+
235102
235070
  this.#asisEditorView.dispatch({
235103
- effects: [
235104
- StateEffect.reconfigure.of(
235105
- EditorView.decorations.of(
235106
- Decoration.set(
235107
- Decoration.line({ attributes: { style: "font-weight: bold" } }).range(0)
235108
- )
235109
- )
235110
- )
235111
- ]
235071
+ effects: [setAsisDecorationsEffect.of(asisDecorations)] // StateField가 처리할 효과
235112
235072
  });
235113
235073
  this.#tobeEditorView.dispatch({
235114
- //effects: [tobeEffect]
235074
+ effects: [setTobeDecorationsEffect.of(tobeDecorations)] // StateField가 처리할 효과
235115
235075
  });
235116
235076
 
235117
- // ⭐️ 3단계: 데코레이션까지 적용된 후 뷰가 다시 안정화될 시간을 한 번 더 줍니다.
235077
+ // 3단계: 데코레이션까지 적용된 후 뷰가 다시 안정화될 시간을 한 번 더 줍니다.
235118
235078
  // 그 다음 프레임에서 스크롤 동기화를 활성화합니다.
235119
235079
  requestAnimationFrame(() => {
235120
235080
  this.#isScrollSyncActive = true;
@@ -235124,23 +235084,8 @@ class IdeDiff extends HTMLElement {
235124
235084
  });
235125
235085
  });
235126
235086
  };
235127
-
235128
- disconnectedCallback() {
235129
- // 컴포넌트 해제 시 스크롤 리스너 제거
235130
- if (this._asisScrollHandler) {
235131
- this.#asisEditorView.scrollDOM.removeEventListener('scroll', this._asisScrollHandler);
235132
- this.#tobeEditorView.scrollDOM.removeEventListener('scroll', this._tobeScrollHandler);
235133
- this._asisScrollHandler = null;
235134
- this._tobeScrollHandler = null;
235135
- }
235136
- if (this.#asisEditorView) {
235137
- this.#asisEditorView.destroy();
235138
- }
235139
- if (this.#tobeEditorView) {
235140
- this.#tobeEditorView.destroy();
235141
- }
235142
- }
235143
235087
  }
235088
+
235144
235089
  customElements.define("ide-diff", IdeDiff);
235145
235090
 
235146
235091
  //import "./components/ideAssi.js";