diff --git a/packages/codemirror/src/extensions/custom_tab.ts b/packages/codemirror/src/extensions/custom_tab.ts index c8ced1df2..3987827dd 100644 --- a/packages/codemirror/src/extensions/custom_tab.ts +++ b/packages/codemirror/src/extensions/custom_tab.ts @@ -24,19 +24,38 @@ const smartIndentWithTab: KeyBinding[] = [ // Step 1: Handle non-empty selections → replace with tab if (selection.ranges.some(range => !range.empty)) { - for (let range of selection.ranges) { - changes.push({ from: range.from, to: range.to, insert: "\t" }); - newSelections.push(EditorSelection.cursor(range.from + 1)); + // If multiple lines are selected, insert a tab character at the start of each line + // and move the cursor to the position after the tab character. + const linesCovered = new Set(); + for (const range of selection.ranges) { + const startLine = state.doc.lineAt(range.from); + const endLine = state.doc.lineAt(range.to); + + for (let lineNumber = startLine.number; lineNumber <= endLine.number; lineNumber++) { + linesCovered.add(lineNumber); + } + } + + if (linesCovered.size > 1) { + // Multiple lines are selected, indent each line. + return indentMore({ state, dispatch }); + } else { + // Single line selection, replace with tab. + for (let range of selection.ranges) { + changes.push({ from: range.from, to: range.to, insert: "\t" }); + newSelections.push(EditorSelection.cursor(range.from + 1)); + } + + dispatch( + state.update({ + changes, + selection: EditorSelection.create(newSelections), + scrollIntoView: true, + userEvent: "input" + }) + ); } - dispatch( - state.update({ - changes, - selection: EditorSelection.create(newSelections), - scrollIntoView: true, - userEvent: "input" - }) - ); return true; }