Browse Source

improve useInsertPrefix hooks

WNomunomu 1 year ago
parent
commit
35e9b67134

+ 54 - 12
packages/editor/src/client/services/use-codemirror-editor/utils/insert-prefix.ts

@@ -11,26 +11,68 @@ export const useInsertPrefix = (view?: EditorView): InsertPrefix => {
       return;
     }
 
-    // get the line numbers of the selected range
     const { from, to } = view.state.selection.main;
     const startLine = view.state.doc.lineAt(from);
     const endLine = view.state.doc.lineAt(to);
 
-    // Insert prefix for each line
-    const lines: ChangeSpec[] = [];
-    let insertTextLength = 0;
+    let allLinesHavePrefix = true;
     for (let i = startLine.number; i <= endLine.number; i++) {
       const line = view.state.doc.line(i);
-      const insertText = noSpaceIfPrefixExists && line.text.startsWith(prefix)
-        ? prefix
-        : `${prefix} `;
-      insertTextLength += insertText.length;
-      lines.push({ from: line.from, insert: insertText });
+      const trimmedLine = line.text.trim();
+      if (trimmedLine !== '' && !trimmedLine.startsWith(prefix)) {
+        allLinesHavePrefix = false;
+        break;
+      }
     }
-    view.dispatch({ changes: lines });
 
-    // move the cursor to the end of the selected line
-    view.dispatch({ selection: { anchor: endLine.to + insertTextLength } });
+    const changes: ChangeSpec[] = [];
+    let totalLengthChange = 0;
+
+    for (let i = startLine.number; i <= endLine.number; i++) {
+      const line = view.state.doc.line(i);
+      const trimmedLine = line.text.trim();
+
+      if (trimmedLine === '') {
+        continue;
+      }
+
+      const leadingSpaces = line.text.match(/^\s*/)?.[0] || '';
+      const contentTrimmed = line.text.trimStart();
+
+      if (allLinesHavePrefix) {
+        const contentStartMatch = line.text.match(new RegExp(`^\\s*${prefix}\\s+`));
+        if (contentStartMatch) {
+          const prefixWithSpaces = contentStartMatch[0];
+          const indentLevel = Math.floor(leadingSpaces.length / 2) * 2; // Preserve indent level
+          const newIndent = ' '.repeat(indentLevel);
+
+          changes.push({
+            from: line.from,
+            to: line.from + prefixWithSpaces.length,
+            insert: newIndent,
+          });
+
+          totalLengthChange -= (prefixWithSpaces.length - newIndent.length);
+        }
+      }
+      else {
+        const insertText = `${leadingSpaces}${prefix} ${contentTrimmed}`;
+        changes.push({
+          from: line.from,
+          to: line.to,
+          insert: insertText,
+        });
+        totalLengthChange += (insertText.length - line.text.length);
+      }
+    }
+
+    view.dispatch({ changes });
+
+    view.dispatch({
+      selection: {
+        anchor: endLine.to + totalLengthChange,
+      },
+    });
     view.focus();
   }, [view]);
 };