Skip to content
File

Blob: src/client/components/editor/extensions/code-block/extension.ts

typescript63 lines
1import { textblockTypeInputRule } from "@tiptap/core";
2import { Plugin, TextSelection } from "@tiptap/pm/state";
3import { ReactNodeViewRenderer } from "@tiptap/react";
4import { SharedCodeBlock } from "@/shared/editor/schema";
5import { resolveLanguage } from "@/shared/editor/schema/code-block";
6import { resolveCodeBlockLineRange } from "./selection";
7import { CodeBlockView } from "./view";
8import { createLazyHighlightPlugin } from "./lazy-highlight";
9 
10function createCodeBlockTripleClickPlugin(codeBlockName: string) {
11 return new Plugin({
12 props: {
13 handleTripleClick(view, pos, event) {
14 if (event.button !== 0) return false;
15 
16 const $pos = view.state.doc.resolve(pos);
17 if ($pos.parent.type.name !== codeBlockName) return false;
18 
19 const range = resolveCodeBlockLineRange($pos.parent.textContent, $pos.parentOffset);
20 const lineSelection = TextSelection.create(view.state.doc, $pos.start() + range.from, $pos.start() + range.to);
21 
22 if (!view.state.selection.eq(lineSelection)) {
23 view.dispatch(view.state.tr.setSelection(lineSelection).setMeta("pointer", true));
24 } else if (!view.hasFocus()) {
25 view.focus();
26 }
27 
28 event.preventDefault();
29 return true;
30 },
31 },
32 });
33}
34 
35export const HighlightedCodeBlock = SharedCodeBlock.extend({
36 addNodeView() {
37 return ReactNodeViewRenderer(CodeBlockView);
38 },
39 
40 addProseMirrorPlugins() {
41 return [
42 ...(this.parent?.() ?? []),
43 createCodeBlockTripleClickPlugin(this.name),
44 createLazyHighlightPlugin(this.name, this.options.defaultLanguage),
45 ];
46 },
47 
48 addInputRules() {
49 return [
50 textblockTypeInputRule({
51 find: /^```([a-z]+)?[\s\n]$/,
52 type: this.type,
53 getAttributes: (match) => ({ language: resolveLanguage(match[1]) }),
54 }),
55 textblockTypeInputRule({
56 find: /^~~~([a-z]+)?[\s\n]$/,
57 type: this.type,
58 getAttributes: (match) => ({ language: resolveLanguage(match[1]) }),
59 }),
60 ];
61 },
62});