Skip to content

new-log-viewer: Add custom Monaco editor themes and a Monaco language for logs. #69

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

Merged
merged 8 commits into from
Sep 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions new-log-viewer/src/components/Editor/MonacoInstance/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@ import "./index.css";


interface MonacoEditorProps {
actions: ActionType[],
lineNum: number,
text: string,
actions: ActionType[],
themeName: "dark" | "light",

beforeMount?: BeforeMountCallback,
beforeTextUpdate?: BeforeTextUpdateCallback,
onCursorExplicitPosChange: CursorExplicitPosChangeCallback,
Expand All @@ -40,9 +42,10 @@ interface MonacoEditorProps {
* the editor.
*
* @param props
* @param props.actions
* @param props.lineNum
* @param props.text
* @param props.actions
* @param props.themeName
* @param props.beforeMount
* @param props.beforeTextUpdate
* @param props.onCursorExplicitPosChange
Expand All @@ -52,9 +55,10 @@ interface MonacoEditorProps {
* @return
*/
const MonacoInstance = ({
actions,
lineNum,
text,
actions,
themeName,
beforeMount,
beforeTextUpdate,
onMount,
Expand Down Expand Up @@ -98,6 +102,11 @@ const MonacoInstance = ({
onMount,
]);

// On `themeName` update, set the theme in the editor.
useEffect(() => {
monaco.editor.setTheme(themeName);
}, [themeName]);

// On `text` update, set the text and position cursor in the editor.
useEffect(() => {
if (null === editorRef.current) {
Expand Down
55 changes: 55 additions & 0 deletions new-log-viewer/src/components/Editor/MonacoInstance/language.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import * as monaco from "monaco-editor/esm/vs/editor/editor.api.js";

import {TOKEN_NAME} from "./typings";


const LOG_LANGUAGE_NAME = "logLanguage";


/**
* Registers a custom log language in the Monaco editor.
*/
const setupCustomLogLanguage = () => {
monaco.languages.register({
id: LOG_LANGUAGE_NAME,
});
monaco.languages.setMonarchTokensProvider(LOG_LANGUAGE_NAME, {
tokenizer: {
root: [
[
"INFO",
TOKEN_NAME.CUSTOM_INFO,
],
[
"WARN",
TOKEN_NAME.CUSTOM_WARN,
],
[
"ERROR",
TOKEN_NAME.CUSTOM_ERROR,
],
[
"FATAL",
TOKEN_NAME.CUSTOM_FATAL,
],
[
/(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3})Z/,
TOKEN_NAME.CUSTOM_DATE,
],
[
/^[\t ]*at.*$/,
TOKEN_NAME.CUSTOM_EXCEPTION,
],
[
/(\d+(?:\.\d+)?([eE])([+-])[0-9](\.[0-9])?|\d+(?:\.\d+)?)/,
TOKEN_NAME.CUSTOM_NUMBER,
],
],
},
});
};

export {
LOG_LANGUAGE_NAME,
setupCustomLogLanguage,
};
45 changes: 45 additions & 0 deletions new-log-viewer/src/components/Editor/MonacoInstance/theme.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import * as monaco from "monaco-editor/esm/vs/editor/editor.api.js";

import {THEME_NAME} from "../../../typings/config";
import {TOKEN_NAME} from "./typings";


/**
* Sets up custom themes for the Monaco editor.
*/
const setupThemes = () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor nit: Grammatically, this should be setUpThemes since setup is a noun, not a verb. Feel free to ignore if you think it's more confusing.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about initThemes?

On the other hand, for consistency we should rename the other functions as well. Any objection if we do the renaming in the same PR?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mm, that might touch a lot of places. We could leave it as setupXxx for now and do the refactoring in another PR.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure

monaco.editor.defineTheme(THEME_NAME.DARK, {
base: "vs-dark",
inherit: true,
rules: [
{token: TOKEN_NAME.CUSTOM_INFO, foreground: "#098658"},
{token: TOKEN_NAME.CUSTOM_WARN, foreground: "#ce9178"},
{token: TOKEN_NAME.CUSTOM_ERROR, foreground: "#ce9178", fontStyle: "bold"},
{token: TOKEN_NAME.CUSTOM_FATAL, foreground: "#ce9178", fontStyle: "bold"},
{token: TOKEN_NAME.CUSTOM_DATE, foreground: "#529955"},
{token: TOKEN_NAME.CUSTOM_EXCEPTION, foreground: "#ce723b", fontStyle: "italic"},
{token: TOKEN_NAME.CUSTOM_NUMBER, foreground: "#3f9ccb"},
{token: TOKEN_NAME.COMMENT, foreground: "#008000"},
],
colors: {
"editor.lineHighlightBackground": "#3c3c3c",
},
});
monaco.editor.defineTheme(THEME_NAME.LIGHT, {
base: "vs",
inherit: true,
rules: [
{token: TOKEN_NAME.CUSTOM_INFO, foreground: "#098658"},
{token: TOKEN_NAME.CUSTOM_WARN, foreground: "#b81560"},
{token: TOKEN_NAME.CUSTOM_ERROR, foreground: "#ac1515", fontStyle: "bold"},
{token: TOKEN_NAME.CUSTOM_FATAL, foreground: "#ac1515", fontStyle: "bold"},
{token: TOKEN_NAME.CUSTOM_DATE, foreground: "#008000"},
{token: TOKEN_NAME.CUSTOM_EXCEPTION, foreground: "#ce723b", fontStyle: "italic"},
{token: TOKEN_NAME.CUSTOM_NUMBER, foreground: "#3f9ccb"},
],
colors: {},
});
};


export {setupThemes};
12 changes: 12 additions & 0 deletions new-log-viewer/src/components/Editor/MonacoInstance/typings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@ import * as monaco from "monaco-editor/esm/vs/editor/editor.api.js";
import {ACTION_NAME} from "../../../utils/actions";


enum TOKEN_NAME {
CUSTOM_INFO = "customInfo",
CUSTOM_WARN = "customWarn",
CUSTOM_ERROR = "customError",
CUSTOM_FATAL = "customFatal",
CUSTOM_DATE = "customDate",
CUSTOM_EXCEPTION = "customException",
CUSTOM_NUMBER = "customNumber",
COMMENT = "comment",
}

/**
* Gets called when the cursor position is explicitly changed in the editor.
*
Expand Down Expand Up @@ -55,6 +66,7 @@ interface CustomMonacoEditorHandlers {
onCustomAction?: CustomActionCallback,
}

export {TOKEN_NAME};
export type {
BeforeMountCallback,
BeforeTextUpdateCallback,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ import {
setupFocusOnBacktickDown,
setupMobileZoom,
} from "./actions";
import {
LOG_LANGUAGE_NAME,
setupCustomLogLanguage,
} from "./language";
import {setupThemes} from "./theme";
import {CustomMonacoEditorHandlers} from "./typings";


Expand Down Expand Up @@ -38,12 +43,16 @@ const createMonacoEditor = (
actions: ActionType[],
handlers: CustomMonacoEditorHandlers
): monaco.editor.IStandaloneCodeEditor => {
setupCustomLogLanguage();
setupThemes();

const editor = monaco.editor.create(
editorContainer,
{
// eslint-disable-next-line no-warning-comments
// TODO: Add custom observer to debounce automatic layout
automaticLayout: true,
language: LOG_LANGUAGE_NAME,
maxTokenizationLineLength: 30_000,
mouseWheelZoom: true,
readOnly: true,
Expand Down
40 changes: 25 additions & 15 deletions new-log-viewer/src/components/Editor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,18 @@ import {

import * as monaco from "monaco-editor/esm/vs/editor/editor.api.js";

import {useColorScheme} from "@mui/joy";

import {StateContext} from "../../contexts/StateContextProvider";
import {
updateWindowUrlHashParams,
UrlContext,
} from "../../contexts/UrlContextProvider";
import {Nullable} from "../../typings/common";
import {CONFIG_KEY} from "../../typings/config";
import {
CONFIG_KEY,
THEME_NAME,
} from "../../typings/config";
import {BeginLineNumToLogEventNumMap} from "../../typings/worker";
import {
ACTION_NAME,
Expand All @@ -36,12 +41,28 @@ import {goToPositionAndCenter} from "./MonacoInstance/utils";
import "./index.css";


/**
* Resets the cached page size in case it causes a client OOM. If it doesn't, the saved value
* will be restored when {@link restoreCachedPageSize} is called.
*/
const resetCachedPageSize = () => {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this was pulled out from Editor to avoid max lines lint violation.

const error = setConfig(
{key: CONFIG_KEY.PAGE_SIZE, value: CONFIG_DEFAULT[CONFIG_KEY.PAGE_SIZE]}
);

if (null !== error) {
console.error(`Unexpected error returned by setConfig(): ${error}`);
}
};

/**
* Renders a read-only editor for viewing logs.
*
* @return
*/
const Editor = () => {
const {mode, systemMode} = useColorScheme();

const {beginLineNumToLogEventNum, logData, numEvents} = useContext(StateContext);
const {logEventNum} = useContext(UrlContext);

Expand Down Expand Up @@ -100,20 +121,6 @@ const Editor = () => {
});
}, []);

/**
* Resets the cached page size in case it causes a client OOM. If it doesn't, the saved value
* will be restored when {@link restoreCachedPageSize} is called.
*/
const resetCachedPageSize = useCallback(() => {
const error = setConfig(
{key: CONFIG_KEY.PAGE_SIZE, value: CONFIG_DEFAULT[CONFIG_KEY.PAGE_SIZE]}
);

if (null !== error) {
console.error(`Unexpected error returned by setConfig(): ${error}`);
}
}, []);

/**
* Restores the cached page size that was unset in {@link resetCachedPageSize};
*/
Expand Down Expand Up @@ -192,6 +199,9 @@ const Editor = () => {
beforeTextUpdate={resetCachedPageSize}
lineNum={lineNum}
text={logData}
themeName={(("system" === mode) ?
systemMode :
mode) ?? THEME_NAME.DARK}
onCursorExplicitPosChange={handleCursorExplicitPosChange}
onCustomAction={handleEditorCustomAction}
onMount={handleMount}
Expand Down