diff --git a/packages/codemirror/src/extensions/custom_tab.ts b/packages/codemirror/src/extensions/custom_tab.ts new file mode 100644 index 000000000..ae99e90a6 --- /dev/null +++ b/packages/codemirror/src/extensions/custom_tab.ts @@ -0,0 +1,43 @@ +import { indentLess, indentMore } from "@codemirror/commands"; +import type { KeyBinding } from "@codemirror/view"; + +const smartIndentWithTab: KeyBinding[] = [ + { + key: "Tab", + run({ state, dispatch}) { + const { selection } = state; + + for (const range of selection.ranges) { + if (!range.empty) { + // Allow default behaviour. + return false; + } + + const line = state.doc.lineAt(range.head); + const beforeCursor = state.doc.sliceString(line.from, range.head); + + if (/^\s*$/.test(beforeCursor)) { + // Only whitespace before cursor: indent line + return indentMore({state, dispatch}); + } else { + // Insert a tab character + const cursor = range.head; + dispatch(state.update({ + changes: { + from: cursor, + insert: "\t" + }, + selection: { anchor: cursor + 1 }, + scrollIntoView: true, + userEvent: "input" + })); + return true; + } + } + + return false; + }, + shift: indentLess + }, +] +export default smartIndentWithTab; diff --git a/packages/codemirror/src/eslint.spec.ts b/packages/codemirror/src/extensions/eslint.spec.ts similarity index 100% rename from packages/codemirror/src/eslint.spec.ts rename to packages/codemirror/src/extensions/eslint.spec.ts diff --git a/packages/codemirror/src/eslint.ts b/packages/codemirror/src/extensions/eslint.ts similarity index 100% rename from packages/codemirror/src/eslint.ts rename to packages/codemirror/src/extensions/eslint.ts diff --git a/packages/codemirror/src/index.ts b/packages/codemirror/src/index.ts index 1fdd87109..cbb268170 100644 --- a/packages/codemirror/src/index.ts +++ b/packages/codemirror/src/index.ts @@ -5,6 +5,7 @@ import { Compartment, type Extension } from "@codemirror/state"; import { highlightSelectionMatches } from "@codemirror/search"; import { vim } from "@replit/codemirror-vim"; import byMimeType from "./syntax_highlighting.js"; +import smartIndentWithTab from "./extensions/custom_tab.js"; type ContentChangedListener = () => void; @@ -45,7 +46,7 @@ export default class CodeMirror extends EditorView { keymap.of([ ...defaultKeymap, ...historyKeymap, - indentWithTab + ...smartIndentWithTab ]) ] diff --git a/packages/codemirror/src/syntax_highlighting.ts b/packages/codemirror/src/syntax_highlighting.ts index 48704dc8c..ca10bd9f2 100644 --- a/packages/codemirror/src/syntax_highlighting.ts +++ b/packages/codemirror/src/syntax_highlighting.ts @@ -4,7 +4,7 @@ import type { Extension } from "@codemirror/state"; async function buildJavaScript(mimeType: string) { const { javascript, esLint } = await import('@codemirror/lang-javascript'); - const lint = (await import("./eslint.js")).lint; + const lint = (await import("./extensions/eslint.js")).lint; const extensions: Extension[] = [ javascript() ]; const result = await lint(mimeType);