From ec8ccc13279aed55c740a3474e1d990966a90ef5 Mon Sep 17 00:00:00 2001
From: winjo <winjo.gwj@antgroup.com>
Date: Fri, 13 Sep 2024 15:04:54 +0800
Subject: [PATCH] chore: add editor save and update example

---
 packages/startup/src/provider/index.tsx | 110 ++++++++++++++----------
 packages/startup/src/provider/module.ts |  63 ++++++++++++--
 2 files changed, 124 insertions(+), 49 deletions(-)

diff --git a/packages/startup/src/provider/index.tsx b/packages/startup/src/provider/index.tsx
index e3375ec7..f68e522a 100644
--- a/packages/startup/src/provider/index.tsx
+++ b/packages/startup/src/provider/index.tsx
@@ -2,7 +2,7 @@ import { AppProvider, CodeEditor, DiffEditor } from '@codeblitzjs/ide-core';
 import React, { useEffect, useState } from 'react';
 import { createRoot } from 'react-dom/client';
 import '@codeblitzjs/ide-core/languages';
-import { SampleModule, diffsDeferred } from './module'
+import { SampleModule, diffService } from './module'
 import '../index.css';
 import './index.css'
 
@@ -21,54 +21,76 @@ const App = () => {
         newFileContent: 'const add = (x, y) => {\n  return x + y + 1\n}'
       }]
       setDiffs(diffs)
-      diffsDeferred.resolve(diffs)
+      diffService.updateData(diffs)
     }, 1000)
+
+    return () => {
+      diffService.clear()
+    }
   }, [])
 
-  if (!diffs) return null
+  const update = () => {
+    const diffs = [{
+      filePath: 'a1.js',
+      oldFileContent: 'const add = (x, y) => {\n  return x + y\n}',
+      newFileContent: 'const add = (x, y) => {\n  return x + y + 2\n}'
+    }, {
+      filePath: 'a2.js',
+      oldFileContent: 'const add = (x, y) => {\n  return x + y\n}',
+      newFileContent: 'const sub = (x, y) => {\n  return x - y\n}'
+    }]
+    setDiffs(diffs)
+    diffService.updateData(diffs)
+  }
 
   return (
-    <AppProvider
-      appConfig={{
-        workspaceDir: 'my-workspace',
-        layoutConfig: {},
-        modules: [SampleModule],
-      }}
-      runtimeConfig={{
-        biz: 'startup',
-      }}
-    >
-      {diffs.map(({ filePath, oldFileContent, newFileContent }) => {
-        if (!oldFileContent) {
-          return (
-            <CodeEditor
-              key={filePath}
-              uri={`sample://new/${filePath}`}
-              style={{ width: 1000, height: 300, marginBottom: 16 }}
-              editorOptions={{
-                scrollbar: {
-                  alwaysConsumeMouseWheel: false
-                }
-              }}
-            />
-          )
-        } else {
-          return (
-            <DiffEditor
-              key={filePath}
-              originalUri={`sample://old/${filePath}`}
-              modifiedUri={`sample://new/${filePath}`}
-              editorOptions={{
-                scrollbar: {
-                  alwaysConsumeMouseWheel: false
-                }
-              }}
-              style={{ width: 1000, height: 300 }}
-            />
-          )
-        }
-      })}
-    </AppProvider>
+    <>
+      <button onClick={update} style={{ marginBottom: 16 }}>更新</button>
+      <AppProvider
+        appConfig={{
+          workspaceDir: 'my-workspace',
+          modules: [SampleModule],
+          defaultPreferences: {
+            'editor.autoSave': 'afterDelay',
+            'editor.autoSaveDelay': 1000
+          }
+        }}
+        runtimeConfig={{
+          biz: 'startup',
+        }}
+      >
+        {diffs.map(({ filePath, oldFileContent, newFileContent }) => {
+          if (!oldFileContent) {
+            return (
+              <CodeEditor
+                key={filePath}
+                uri={`sample://new/${filePath}`}
+                style={{ width: 1000, height: 300, marginBottom: 16 }}
+                editorOptions={{
+                  scrollbar: {
+                    alwaysConsumeMouseWheel: false
+                  }
+                }}
+              />
+            )
+          } else {
+            return (
+              <DiffEditor
+                key={filePath}
+                originalUri={`sample://old/${filePath}`}
+                modifiedUri={`sample://new/${filePath}`}
+                editorOptions={{
+                  scrollbar: {
+                    alwaysConsumeMouseWheel: false
+                  }
+                }}
+                style={{ width: 1000, height: 300, marginBottom: 16 }}
+              />
+            )
+          }
+        })}
+      </AppProvider>
+    </>
   )
 };
 
diff --git a/packages/startup/src/provider/module.ts b/packages/startup/src/provider/module.ts
index a04835af..7ba8b4c9 100644
--- a/packages/startup/src/provider/module.ts
+++ b/packages/startup/src/provider/module.ts
@@ -1,18 +1,67 @@
 import { Autowired, Injectable, Provider } from '@opensumi/di';
 import { BrowserModule } from '@opensumi/ide-core-browser';
 import { IEditorDocumentModelContentProvider, BrowserEditorContribution, IEditorDocumentModelContentRegistry } from '@opensumi/ide-editor/lib/browser'
-import { URI, Emitter, Event, Domain, Deferred } from '@opensumi/ide-core-common'
+import { URI, Emitter, Event, Domain, IEditorDocumentChange, IEditorDocumentModelSaveResult, SaveTaskResponseState } from '@opensumi/ide-core-common'
 
-export const diffsDeferred = new Deferred<{filePath: string, oldFileContent: string | null, newFileContent: string }[]>()
+export interface IDiffData {
+  filePath: string;
+  oldFileContent: string | null;
+  newFileContent: string;
+}
+
+class DiffService {
+  #data: IDiffData[] | null = null
+  #dataEmitter = new Emitter<URI[]>()
+  onDataChange = this.#dataEmitter.event;
+
+  get data() {
+    return this.#data;
+  }
+  updateData(data: IDiffData[]) {
+    const lastData = this.#data
+    this.#data = data
+    const lastDataMap: Record<string, IDiffData> = lastData?.reduce((obj, item) => {
+      obj[item.filePath] = item
+      return obj
+    }, {}) || {}
+    const uris: URI[] = []
+    data.forEach(item => {
+      const lastItem = lastDataMap?.[item.filePath]
+      if (!lastItem) return
+      if (item.oldFileContent !== lastItem.oldFileContent) {
+        uris.push(new URI(`sample://old/${item.filePath}`))
+      }
+      if (item.newFileContent !== lastItem.newFileContent) {
+        uris.push(new URI(`sample://new/${item.filePath}`))
+      }
+    })
+    this.#dataEmitter.fire(uris)
+  }
+
+  clear() {
+    this.#data = null
+  }
+}
+
+export const diffService = new DiffService()
 
 @Injectable()
 export class SampleSchemeDocumentProvider implements IEditorDocumentModelContentProvider {
+  private _onDidChangeContent: Emitter<URI> = new Emitter();
+  onDidChangeContent: Event<URI> = this._onDidChangeContent.event;
+
+  constructor() {
+    diffService.onDataChange((uris) => {
+      uris.forEach(uri => this._onDidChangeContent.fire(uri))
+    })
+  }
+
   handlesScheme(scheme: string) {
     return scheme === 'sample';
   }
 
   async provideEditorDocumentModelContent(uri: URI): Promise<string> {
-    const diffs = await diffsDeferred.promise
+    const diffs = diffService.data || []
     const diff = diffs.find(item => item.filePath === uri.codeUri.path.slice(1))
     if (!diff) return ''
     if (uri.authority === 'new') return diff.newFileContent
@@ -23,8 +72,12 @@ export class SampleSchemeDocumentProvider implements IEditorDocumentModelContent
     return false;
   }
 
-  private _onDidChangeContent: Emitter<URI> = new Emitter();
-  onDidChangeContent: Event<URI> = this._onDidChangeContent.event;
+  async saveDocumentModel(uri: URI, content: string, baseContent: string, changes: IEditorDocumentChange[]): Promise<IEditorDocumentModelSaveResult> {
+    console.log(uri, content, baseContent, changes)
+    return {
+      state: SaveTaskResponseState.SUCCESS,
+    }
+  }
 }
 
 @Domain(BrowserEditorContribution)
