Просмотр исходного кода

Merge branch 'feat/unified-merge-view' into feat/164347-send-only-selected-markdown-range-to-server

Shun Miyazawa 1 год назад
Родитель
Сommit
8302e9fd68

+ 61 - 3
apps/app/src/features/openai/client/services/editor-assistant.ts

@@ -6,6 +6,7 @@ import { GlobalCodeMirrorEditorKey } from '@growi/editor';
 import { acceptChange, rejectChange } from '@growi/editor/dist/client/services/unified-merge-view';
 import { acceptChange, rejectChange } from '@growi/editor/dist/client/services/unified-merge-view';
 import { useCodeMirrorEditorIsolated } from '@growi/editor/dist/client/stores/codemirror-editor';
 import { useCodeMirrorEditorIsolated } from '@growi/editor/dist/client/stores/codemirror-editor';
 import { useSecondaryYdocs } from '@growi/editor/dist/client/stores/use-secondary-ydocs';
 import { useSecondaryYdocs } from '@growi/editor/dist/client/stores/use-secondary-ydocs';
+import { type Text as YText } from 'yjs';
 
 
 import {
 import {
   SseMessageSchema,
   SseMessageSchema,
@@ -49,7 +50,8 @@ type UseEditorAssistant = () => {
 
 
 export const useEditorAssistant: UseEditorAssistant = () => {
 export const useEditorAssistant: UseEditorAssistant = () => {
   // Refs
   // Refs
-  const positionRef = useRef<number>(0);
+  // const positionRef = useRef<number>(0);
+  const lineRef = useRef<number>(0);
 
 
   // States
   // States
   const [selectedTextFirstLineNumber, setSelectedTextFirstLineNumber] = useState<number | undefined>();
   const [selectedTextFirstLineNumber, setSelectedTextFirstLineNumber] = useState<number | undefined>();
@@ -122,6 +124,55 @@ export const useEditorAssistant: UseEditorAssistant = () => {
     });
     });
   }, [mutateIsEnableUnifiedMergeView]);
   }, [mutateIsEnableUnifiedMergeView]);
 
 
+  const insertTextAtLine = (ytext: YText, lineNumber: number, textToInsert: string): void => {
+    // Get the entire text content
+    const content = ytext.toString();
+
+    // Split by newlines to get all lines
+    const lines = content.split('\n');
+
+    // Calculate the index position for insertion
+    let insertPosition = 0;
+
+    // Sum the length of all lines before the target line (plus newline characters)
+    for (let i = 0; i < lineNumber && i < lines.length; i++) {
+      insertPosition += lines[i].length + 1; // +1 for the newline character
+    }
+
+    // Insert the text at the calculated position
+    ytext.insert(insertPosition, textToInsert);
+  };
+
+
+  const getLineInfo = (ytext: YText, lineNumber: number): { text: string, startIndex: number } | null => {
+    // Get the entire text content
+    const content = ytext.toString();
+
+    // Split by newlines to get all lines
+    const lines = content.split('\n');
+
+    // Check if the requested line exists
+    if (lineNumber < 0 || lineNumber >= lines.length) {
+      return null; // Line doesn't exist
+    }
+
+    // Get the text of the specified line
+    const text = lines[lineNumber];
+
+    // Calculate the start index of the line
+    let startIndex = 0;
+    for (let i = 0; i < lineNumber; i++) {
+      startIndex += lines[i].length + 1; // +1 for the newline character
+    }
+
+    // Return comprehensive line information
+    return {
+      text,
+      startIndex,
+    };
+  };
+
+
   const accept = useCallback(() => {
   const accept = useCallback(() => {
     acceptChange(codeMirrorEditor?.view);
     acceptChange(codeMirrorEditor?.view);
     mutateIsEnableUnifiedMergeView(false);
     mutateIsEnableUnifiedMergeView(false);
@@ -161,7 +212,13 @@ export const useEditorAssistant: UseEditorAssistant = () => {
       ydocs.secondaryDoc.transact(() => {
       ydocs.secondaryDoc.transact(() => {
         pendingDetectedDiff.forEach((detectedDiff) => {
         pendingDetectedDiff.forEach((detectedDiff) => {
           if (isReplaceDiff(detectedDiff.data)) {
           if (isReplaceDiff(detectedDiff.data)) {
-            // TODO: https://redmine.weseek.co.jp/issues/164330
+            const lineInfo = getLineInfo(ytext, lineRef.current);
+            if (lineInfo != null && lineInfo.text !== detectedDiff.data.diff.replace) {
+              ytext.delete(lineInfo.startIndex, lineInfo.text.length);
+              insertTextAtLine(ytext, lineRef.current, detectedDiff.data.diff.replace);
+            }
+
+            lineRef.current += 1;
           }
           }
           // if (isInsertDiff(detectedDiff.data)) {
           // if (isInsertDiff(detectedDiff.data)) {
           //   ytext.insert(positionRef.current, detectedDiff.data.diff.insert);
           //   ytext.insert(positionRef.current, detectedDiff.data.diff.insert);
@@ -189,7 +246,8 @@ export const useEditorAssistant: UseEditorAssistant = () => {
       // Set detectedDiff to undefined after applying all detectedDiff to secondaryDoc
       // Set detectedDiff to undefined after applying all detectedDiff to secondaryDoc
       if (detectedDiff?.filter(detectedDiff => detectedDiff.applied === false).length === 0) {
       if (detectedDiff?.filter(detectedDiff => detectedDiff.applied === false).length === 0) {
         setDetectedDiff(undefined);
         setDetectedDiff(undefined);
-        positionRef.current = 0;
+        lineRef.current = 0;
+        // positionRef.current = 0;
       }
       }
     }
     }
   }, [codeMirrorEditor, detectedDiff, ydocs?.secondaryDoc]);
   }, [codeMirrorEditor, detectedDiff, ydocs?.secondaryDoc]);

+ 4 - 0
apps/app/src/features/openai/server/routes/edit/index.ts

@@ -167,6 +167,10 @@ export const postMessageToEditHandlersFactory: PostMessageHandlersFactory = (cro
               - Edit markdown according to user instructions and include it line by line in the 'replace' object. Return original text for lines that do not need editing.
               - Edit markdown according to user instructions and include it line by line in the 'replace' object. Return original text for lines that do not need editing.
               - [At the end of the list] A "message" object that contains your friendly message explaining that the operation was completed and what changes were made.
               - [At the end of the list] A "message" object that contains your friendly message explaining that the operation was completed and what changes were made.
 
 
+              IMPORTANT:
+              - The text for lines that do not need correction must be returned exactly as in the original text.
+              - Include original text in the replace object even if it contains only spaces or line breaks
+
               Always provide messages in the same language as the user's request.`,
               Always provide messages in the same language as the user's request.`,
             },
             },
             // {
             // {