Skip to content

Commit

Permalink
feat: codemirror extension to automatically insert self closing tag o…
Browse files Browse the repository at this point in the history
…nce closed (#45)
  • Loading branch information
YossiSaadi authored Mar 18, 2024
1 parent 658ade1 commit 929a9fc
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 1 deletion.
6 changes: 5 additions & 1 deletion src/codemirror/keymaps/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { KeyBinding } from "@uiw/react-codemirror";
import closingBracket from "./closing-bracket";
import selfClosingTag from "./self-closing-tag";

export default [{ key: ">", run: closingBracket }] satisfies KeyBinding[];
export default [
{ key: ">", run: closingBracket },
{ key: "/", run: selfClosingTag },
] satisfies KeyBinding[];
52 changes: 52 additions & 0 deletions src/codemirror/keymaps/self-closing-tag.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { EditorSelection, EditorView } from "@uiw/react-codemirror";
import {
getEditorStateInfo,
parseTagFromLineText,
} from "../utils/extensions-utils";

function insertSelfClosingTagCommand(view: EditorView): boolean {
const { state, dispatch } = view;
const { cursorPos, lineTextUpToCursor, lineTextAfterCursor } =
getEditorStateInfo(state);

const tagName = parseTagFromLineText(lineTextUpToCursor);

if (!tagName) {
return false;
}

if (!isInsideOpenTag(lineTextUpToCursor)) {
return false;
}

if (isFollowedByCloseTag(lineTextAfterCursor)) {
return false;
}

// +2 to move in after the inserted self-closing bracket
const newCursorPos = EditorSelection.cursor(cursorPos + 2);

// insert self-closing tag syntax ('/>') and adjust the cursor position
dispatch(
state.update({
changes: { from: cursorPos, insert: "/>" },
selection: newCursorPos,
})
);

return true;
}

function isInsideOpenTag(lineTextUpToCursor: string): boolean {
// Checks if the cursor is within an open tag (e.g., after "<Button" or "<Button prop").
return /<\w+[^>]*$/.test(lineTextUpToCursor);
}

function isFollowedByCloseTag(lineTextAfterCursor: string): boolean {
// Checks if the cursor's position in the document is followed by a closing part of a tag or self-closing syntax.
return (
/<\/?\w+>/.test(lineTextAfterCursor) || /\/>/.test(lineTextAfterCursor)
);
}

export default insertSelfClosingTagCommand;

0 comments on commit 929a9fc

Please sign in to comment.