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

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

Closed
caner-cetin opened this issue Oct 13, 2024 · 5 comments
Closed

Comments

@caner-cetin
Copy link

caner-cetin commented Oct 13, 2024

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.

@caner-cetin
Copy link
Author

Also I am fully volunteer to write documentations for “how-to-do X” outside of full demos, but even internal code is too complex for me to navigate.

@CGNonofr
Copy link
Contributor

CGNonofr commented Oct 14, 2024

Ahah there's a lot of concerns here. I am aware that this is a really complex library to use. You have no idea how much time was spent to make it no more complicated than what it already is.

I agree documentation is lacking, but it's also big enough to scare any newcomer, so I'm not sure how to document it properly.

uhhhhhhhhhhhh what? what vscode extension? I have a berlin wall of package.json what do you mean by VSCode extension?

A VScode extension is not a new concept, it's ... a VSCode extension, like one you can install in your VSCode. There are multiple ways of installing it with this library:

  • create your own vsix extension file or download it from the VSCode marketplace, then use the @codingame/monaco-vscode-rollup-vsix-plugin to load it
  • have you extension folder on the disk somewhere, and use the @codingame/monaco-vscode-rollup-extension-directory-plugin to load it
  • use the extension-gallery service override (and required other services overrides) and install your theme extension from the marketplace, just like in VSCode
  • Register the extension programmatically, just like explained in the README (good example of something that is already explained in the documentation but that you aren't aware of, maybe because it's not well-structured enough?)
Uncaught Error: Unable to load extension-file://vscode.theme-defaults/themes/dark_modern.json: Not Found

That errors happens a lot, because the library make use a lot of the new URL(..., import.meta.url) syntax to reference assets. It's the best way out there to do it, and it works well with webpack, but some other builders tend to ignore it. For instance, vite only supports them fully in build mode, and need a custom esbuild plugin in dev mode (that we use in the demo here)

That's probably also the cause of the missing labels

The error is quite misleading though, because the extension file are loaded through a virtual filesystem implementation that transform extension-file urls to real urls imported using your bundler, and the loading error only mention the extension-file url.

Also, there is only a single demo for everything that became really complex. We probably need simpler demos of various supported features now

@caner-cetin
Copy link
Author

Thank you so much for extensive response @CGNonofr, everything works like a charm after configuring Vite, syntax highlighter, themes, workers etc. everything was broken but its working wonderful now.

By the way, I am so sorry if I sounded too aggressive initially. Thank you again <3

@CGNonofr
Copy link
Contributor

Feel free to suggest any change in the documentation that would have make the onboarding simpler for you though!

@caner-cetin
Copy link
Author

caner-cetin commented Oct 14, 2024

Sure, I will try to contribute as much as I can to the examples and documentation ( after i learn inside outs ofc )

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