File size: 3,102 Bytes
3c3f089
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import { useRef, useState } from "react";
import { IKeyboardEvent } from "monaco-editor";
import { useDebounce } from "use-debounce";
import { OnChange, OnMount } from "@monaco-editor/react";
import parserHtml from "prettier/parser-html";
import parserCss from "prettier/parser-postcss";
import parserBabel from "prettier/parser-babel";
import prettier from "prettier";
import { useAppSelector } from "../store/hook";
import { theme_state } from "../store/features/themeSlice";

export const useMonaco = () => {
  const { theme } = useAppSelector(theme_state);
  const codeEditor = useRef<any>();

  const [input, setInput] = useState<string | undefined>("");
  const [code] = useDebounce(input, 1000);

  const onChange: OnChange = (value) => {
    setInput(value);
  };

  const onMount: OnMount = async (monacoEditor, monaco) => {
    codeEditor.current = monacoEditor;

    monaco.editor.defineTheme("myTheme", {
      base: "vs-dark",
      inherit: true,
      rules: [{ background: theme.background, token: "" }],
      colors: {
        "editor.background": theme.foreground,
      },
    });

    monaco.editor.setTheme("myTheme");

    const { default: traverse } = await import("@babel/traverse");
    const { parse } = await import("@babel/parser");
    const { default: MonacoJSXHighlighter } = await import(
      "monaco-jsx-highlighter"
    );

    //jsx syntax highlight
    const babelParse = (code: any) =>
      parse(code, { sourceType: "module", plugins: ["jsx"] });

    const monacoJSXHighlighter = new MonacoJSXHighlighter(
      //@ts-ignore
      monaco,
      babelParse,
      traverse,
      monacoEditor
    );

    monacoJSXHighlighter.highLightOnDidChangeModelContent(
      0,
      () => {},
      () => {},
      undefined,
      () => {}
    );

    //format code
    function formatOnSave() {
      const unformattedCode = codeEditor.current.getModel().getValue();
      const lang = codeEditor.current.getModel()._languageIdentifier.language;

      let config;

      switch (lang) {
        case "html":
          config = { parser: "html", plugin: [parserHtml] };
          break;

        case "css":
          config = { parser: "css", plugin: [parserCss] };
          break;

        case "javascript":
          config = { parser: "babel", plugin: [parserBabel] };
          break;

        default:
          break;
      }

      const formattedCode = prettier.format(unformattedCode, {
        parser: config && config.parser,
        plugins: config && config.plugin,
        useTabs: false,
        semi: true,
      });

      codeEditor.current.setValue(formattedCode);
    }

    //save command
    let handleOnKeyDown = codeEditor.current.onKeyDown(
      (event: IKeyboardEvent) => {
        if (
          (window.navigator.platform.match("Mac")
            ? event.metaKey
            : event.ctrlKey) &&
          event.code === "KeyS"
        ) {
          event.preventDefault();
          formatOnSave();
        }
      }
    );

    //cleaning up
    return () => handleOnKeyDown.dispose();
  };

  return { onMount, onChange, code };
};