Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to integrate Shiki Highlighter #641

Open
ansh opened this issue Aug 14, 2024 · 1 comment
Open

Unable to integrate Shiki Highlighter #641

ansh opened this issue Aug 14, 2024 · 1 comment

Comments

@ansh
Copy link

ansh commented Aug 14, 2024

Describe the bug
I want to integrate Shiki highlighter, but there is a significant delay, and sometimes it doesn't work because I have to make handleEditorWillMount into an async function

To Reproduce

Steps to reproduce the behavior:

  1. Integrate Monaco React
  2. Try to integrate Shiki editor as follows
  const handleEditorWillMount: BeforeMount = async (monaco) => {

    // Create the highlighter, it can be reused
    const highlighter = await createHighlighter({
      themes: ["slack-dark", "vitesse-dark", "vitesse-light"],
      langs: ["javascript", "typescript", "css", "html", "json"],
    })
    // Register the languageIds first. Only registered languages will be highlighted.
    monaco.languages.register({ id: "typescript" })
    monaco.languages.register({ id: "javascript" })
    monaco.languages.register({ id: "css" })
    monaco.languages.register({ id: "html" })
    monaco.languages.register({ id: "json" })
    // Register the themes from Shiki, and provide syntax highlighting for Monaco.
    shikiToMonaco(highlighter, monaco)
  }

But this has a delay so it doesn't work properly. If I save highlighter into a state variable, then it doesn't work either.

Any workarounds since createHighlighter is async?

Expected behavior
No delay, full integration

Desktop (please complete the following information):

  • OS: MacOS
  • Browser Chrome
  • Version Latest
@NGC2207
Copy link

NGC2207 commented Dec 16, 2024

This is my code, inspired by a demo I saw on GitHub, but I can't locate it now.
code-editor.tsx:

"use client";

import "@fontsource-variable/fira-code";
import { createHighlighter } from "shiki";
import type { editor } from "monaco-editor";
import { shikiToMonaco } from "@shikijs/monaco";
import { useEffect, useRef, useMemo } from "react";
import { useCodeEditorStore } from "@/store/codeEditorStore";
import MonacoEditor, { type Monaco } from "@monaco-editor/react";

const ADDITIONAL_THEMES = [
"andromeeda",
"aurora-x",
"ayu-dark",
"catppuccin-frappe",
"catppuccin-latte",
"catppuccin-macchiato",
"catppuccin-mocha",
"dark-plus",
"dracula",
"dracula-soft",
"one-dark-pro",
"vitesse-dark",
"vitesse-light",
];

const ADDITIONAL_LANGUAGES = ["c", "java"] as const satisfies Parameters<
typeof createHighlighter

[0]["langs"];

export function CodeEditor() {
const monacoRef = useRef<Monaco | null>(null);
const editorRef = useRef<editor.IStandaloneCodeEditor | null>(null);
const { lang, theme, value, isLigature } = useCodeEditorStore();

useEffect(() => {
if (monacoRef.current && editorRef.current) {
monacoRef.current.editor.setTheme(theme);
}
}, [theme]);

const options = useMemo(
() => ({
minimap: { enabled: false },
fontSize: 14,
fontFamily: "Fira Code Variable, monospace",
tabSize: 4,
showFoldingControls: "always" as const,
fontLigatures: isLigature,
automaticLayout: true,
guides: {
bracketPairs: true,
indentation: true,
},
}),
[isLigature]
);

const handleEditorMount = async (
editor: editor.IStandaloneCodeEditor,
monaco: Monaco
) => {
editorRef.current = editor;
monacoRef.current = monaco;

for (const lang of ADDITIONAL_LANGUAGES) {
  monacoRef.current?.languages.register({ id: lang });
}

const highlighter = await createHighlighter({
  themes: ADDITIONAL_THEMES,
  langs: ADDITIONAL_LANGUAGES,
});

shikiToMonaco(highlighter, monacoRef.current);

};

return (

);
}

import { create } from "zustand";

interface CodeEditorState {
lang: string;
theme: string;
value: string;
isLigature: boolean;
setLang: (lang: string) => void;
setTheme: (theme: string) => void;
setValue: (value: string) => void;
setIsLigature: (isLigature: boolean) => void;
}

export const useCodeEditorStore = create((set) => ({
lang: "c",
theme: "one-dark-pro",
value: "",
isLigature: false,
setLang: (lang) => set({ lang }),
setTheme: (theme) => set({ theme }),
setValue: (value) => set({ value }),
setIsLigature: (isLigature) => set({ isLigature }),
}));

codeEditorStore.ts:
import { create } from "zustand";

interface CodeEditorState {
lang: string;
theme: string;
value: string;
isLigature: boolean;
setLang: (lang: string) => void;
setTheme: (theme: string) => void;
setValue: (value: string) => void;
setIsLigature: (isLigature: boolean) => void;
}

export const useCodeEditorStore = create((set) => ({
lang: "c",
theme: "one-dark-pro",
value: "",
isLigature: false,
setLang: (lang) => set({ lang }),
setTheme: (theme) => set({ theme }),
setValue: (value) => set({ value }),
setIsLigature: (isLigature) => set({ isLigature }),
}));

It can achieve a good effect by changing the theme using setTheme.

I'm currently trying to collect LSPs. If you're doing something similar, could you share some of your experiences with me?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants