Skip to content

I have officially spent four hours of my lifespan to set a color theme. #510

@caner-cetin

Description

@caner-cetin

Preface, I am not saying that "your library is shit", both packages/foundations are a godsend, they are perfect for an all-in-one batteries included Monaco setup. Both libs together creates a new level above Monaco, making a high-level structure and this is awesome! Idea of "plug-in monaco setup" sounds awesome, implementation is awesome, everything about it is awesome. Except using it. Entry barrier is higher than Mount Everest, entire thing sets a new level of complexity, documentation is severely lacking to a non existent. Using both libraries for the first time is insanely hard, harder than Haskell, harder than writing a HTTP server in COBOL.

I have a theme. https://github.com/sainnhe/gruvbox-material-vscode/blob/master/themes/gruvbox-material-dark.json. A VSCode theme. What is the sane way to use it? Throw it to https://vsctim.vercel.app/, then get the Monaco editor compatible JSON,
then

      monaco.editor.defineTheme('gruvbox-material-dark', gruvboxMaterialDark)
      monaco.editor.setTheme('gruvbox-material-dark')

bing, right?

Uncaught (in promise) TypeError: standaloneThemeService.defineTheme is not a function

hmmm, lets look at the issue. #458 okay, that makes sense, I have set theme services

			userServices: {
				...getEditorServiceOverride(useOpenEditorStub),
				...getKeybindingsServiceOverride(),
				...getVscodeEditorServiceOverride(useOpenEditorStub),
				...getThemeServiceOverride()
			},

but...
resim

you are expected to use a VSCode extension to declare it.

uhhhhhhhhhhhh what? what vscode extension? I have a berlin wall of package.json what do you mean by VSCode extension?
resim
but okay, I can live with default themes.
resim
hmm... there is something wrong... it looks like labels are not loaded...

		editorAppConfig: {
			$type: "extended",
			codeResources: {
				main: {
					text: code,
					uri: codeUri,
				},
			},
			loadThemes: true,
			useDiffEditor: false,
			monacoWorkerFactory: configureMonacoWorkers,
			htmlContainer: document.getElementById("monaco-editor-root")!,
		},

loadThemes is set to True in monaco-editor-wrapper.WrapperConfig. so when monaco-editor-wrapper initializes, I also import the default extension.

    override async init() {
        if (this.config.loadThemes ?? true) {
            await import('@codingame/monaco-vscode-theme-defaults-default-extension');
        }

makes sense! lets set our theme

Uncaught Error: Unable to load extension-file://vscode.theme-defaults/themes/dark_modern.json: Not Found

...what?
resim
there is default themes under the @codingame/monaco-vscode-theme-defaults-default-extension so what is wrong? where am I supposed to look at? what is going on here? where should I take reference? custom color themes does not work, default colors does not work, there is no documentation for it, what am I supposed to do here?

WrapperConfig

import * as vscode from "vscode";
import getEditorServiceOverride from "@codingame/monaco-vscode-editor-service-override";
import getKeybindingsServiceOverride from "@codingame/monaco-vscode-keybindings-service-override";
import getVscodeEditorServiceOverride from "@codingame/monaco-vscode-editor-service-override";
import getThemeServiceOverride from "@codingame/monaco-vscode-theme-service-override"
import "@codingame/monaco-vscode-python-default-extension";
import { LogLevel } from "vscode/services";
import { createUrl, type WrapperConfig } from "monaco-editor-wrapper";
import { useOpenEditorStub } from "monaco-editor-wrapper/vscode/services";
import type { MonacoLanguageClient } from "monaco-languageclient";
import {
	toSocket,
	WebSocketMessageReader,
	WebSocketMessageWriter,
} from "vscode-ws-jsonrpc";
import { MonacoEditorWrapperProps } from "../components/Editor";
import { configureMonacoWorkers } from "./configureLSPWorkers";

export const CreatePythonUserConfig = (
	workspaceRoot: string,
	code: string,
	codeUri: string,
	props: MonacoEditorWrapperProps,
): WrapperConfig => {
	const url = createUrl({
		secured: props.lspSecured,
		host: props.lspHost,
		port: props.lspPort,
		path: props.lspPath,
	});
	const webSocket = new WebSocket(url);
	const iWebSocket = toSocket(webSocket);
	const reader = new WebSocketMessageReader(iWebSocket);
	const writer = new WebSocketMessageWriter(iWebSocket);

	return {
		languageClientConfigs: {
			python: {
				languageId: "python",
				name: "Python Language Server Example",
				connection: {
					options: {
						$type: "WebSocketDirect",
						webSocket: webSocket,
						startOptions: {
							onCall: (languageClient?: MonacoLanguageClient) => {
								setTimeout(() => {
									// biome-ignore lint/complexity/noForEach: <explanation>
									["pyright.restartserver", "pyright.organizeimports"].forEach(
										(cmdName) => {
											vscode.commands.registerCommand(
												cmdName,
												(...args: unknown[]) => {
													languageClient?.sendRequest(
														"workspace/executeCommand",
														{ command: cmdName, arguments: args },
													);
												},
											);
										},
									);
								}, 250);
							},
							reportStatus: true,
						},
					},
					messageTransports: { reader, writer },
				},
				clientOptions: {
					documentSelector: ["python"],
					workspaceFolder: {
						index: 0,
						name: "workspace",
						uri: vscode.Uri.parse(workspaceRoot),
					},
				},
			},
		},
		logLevel: LogLevel.Debug,
		vscodeApiConfig: {
			userServices: {
				...getEditorServiceOverride(useOpenEditorStub),
				...getKeybindingsServiceOverride(),
				...getVscodeEditorServiceOverride(useOpenEditorStub),
				...getThemeServiceOverride()
			},
			userConfiguration: {
				json: JSON.stringify({
					"workbench.colorTheme": "Default Dark Modern",
					"editor.guides.bracketPairsHorizontal": "active",
					"editor.wordBasedSuggestions": "off",
					// "editor.experimental.asyncTokenization": true,
				}),
			},
		},
		editorAppConfig: {
			$type: "extended",
			codeResources: {
				main: {
					text: code,
					uri: codeUri,
				},
			},
			loadThemes: true,
			useDiffEditor: false,
			monacoWorkerFactory: configureMonacoWorkers,
			htmlContainer: document.getElementById("monaco-editor-root")!,
		},
	};
};

Monaco

import React, { useState, useEffect, useRef, StrictMode } from 'react'
import '@codingame/monaco-vscode-python-default-extension';
import { createFileRoute } from '@tanstack/react-router'
import { MonacoEditorLanguageClientWrapper } from 'monaco-editor-wrapper'
import { CreatePythonUserConfig } from '../editor/python'
import { RegisteredFileSystemProvider, RegisteredMemoryFile, registerFileSystemOverlay } from '@codingame/monaco-vscode-files-service-override'
import * as vscode from 'vscode';
import * as monaco from 'monaco-editor'
import { gruvboxMaterialDark } from '../editor/themes/gruvbox-material-dark'

export const Route = createFileRoute('/code')({
  component: MonacoPage,
})

export default function MonacoPage() {
  const editorRef = useRef<MonacoEditorLanguageClientWrapper | null>(null);

  const [editorReady, setEditorReady] = useState(false);
  const wrapper = new MonacoEditorLanguageClientWrapper();
  const wrapperConfig = CreatePythonUserConfig('/workspace', "print('Hello, World!')", '/workspace/script.py', {
    lspHost: 'localhost',
    lspPort: 8080,
    lspPath: 'lsp/pyright',
    lspSecured: false,
  });
  useEffect(() => {
    const initEditor = async () => {
      if (editorRef.current) return;
      const fileSystemProvider = new RegisteredFileSystemProvider(false);
      fileSystemProvider.registerFile(new RegisteredMemoryFile(vscode.Uri.file('/workspace/script.py'), "print('Hello, World!')"));
      registerFileSystemOverlay(1, fileSystemProvider);
      await wrapper.init(wrapperConfig);
      await wrapper.start();
      monaco.editor.defineTheme('gruvbox-material-dark', gruvboxMaterialDark)
      monaco.editor.setTheme('gruvbox-material-dark')
      setEditorReady(true);
    };
    initEditor();
  }, [wrapper, wrapperConfig]);

  return (
    <div>
      <div id="monaco-editor-root" style={{ height: '100vh', maxWidth: '130vh' }} />
    </div>
  )
}

package.json

{
  "name": "otuzbir-tv-frontend",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "tsc -b && vite build",
    "lint": "eslint .",
    "preview": "vite preview"
  },
  "dependencies": {
    "@codingame/monaco-vscode-configuration-service-override": "~10.0.2",
    "@codingame/monaco-vscode-files-service-override": "~10.0.2",
    "@codingame/monaco-vscode-groovy-default-extension": "~10.0.2",
    "@codingame/monaco-vscode-java-default-extension": "~10.0.2",
    "@codingame/monaco-vscode-javascript-default-extension": "~10.0.2",
    "@codingame/monaco-vscode-json-default-extension": "~10.0.2",
    "@codingame/monaco-vscode-keybindings-service-override": "~10.0.2",
    "@codingame/monaco-vscode-lifecycle-service-override": "~10.0.2",
    "@codingame/monaco-vscode-localization-service-override": "~10.0.2",
    "@codingame/monaco-vscode-python-default-extension": "~10.0.2",
    "@codingame/monaco-vscode-standalone-json-language-features": "~10.0.2",
    "@codingame/monaco-vscode-standalone-languages": "~10.0.2",
    "@codingame/monaco-vscode-standalone-typescript-language-features": "~10.0.2",
    "@codingame/monaco-vscode-textmate-service-override": "~10.0.2",
    "@codingame/monaco-vscode-theme-defaults-default-extension": "~10.0.2",
    "@codingame/monaco-vscode-theme-service-override": "~10.0.2",
    "@codingame/monaco-vscode-typescript-basics-default-extension": "~10.0.2",
    "@codingame/monaco-vscode-typescript-language-features-default-extension": "~10.0.2",
    "@typefox/monaco-editor-react": "~6.0.0-next.3",
    "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@~10.0.2",
    "monaco-editor-wrapper": "~6.0.0-next.3",
    "monaco-languageclient": "~9.0.0-next.3",
    "pyright": "~1.1.384",
    "react": "^18.3.1",
    "react-dom": "^18.3.1",
    "vscode": "npm:@codingame/monaco-vscode-api@~10.0.2",
    "vscode-languageclient": "~9.0.1",
    "ws": "~8.18.0"
  },
  "devDependencies": {
    "@eslint/js": "^9.11.1",
    "@tanstack/router-plugin": "^1.65.0",
    "@types/react": "^18.3.11",
    "@types/react-dom": "^18.3.1",
    "@vitejs/plugin-react": "^4.3.2",
    "autoprefixer": "^10.4.20",
    "eslint": "^9.11.1",
    "eslint-plugin-react-hooks": "^5.1.0-rc.0",
    "eslint-plugin-react-refresh": "^0.4.12",
    "globals": "^15.9.0",
    "postcss": "^8.4.47",
    "tailwindcss": "^3.4.13",
    "typescript": "^5.5.3",
    "typescript-eslint": "^8.7.0",
    "vite": "^5.4.8"
  }
}

any help is appreciated, because there is no other resources to be found.

edit: I dont know why WrapperConfig is rendered as 4 space, sorry for that infinite blackhole.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions