Skip to content

Commit 1d5d95e

Browse files
authored
new-log-viewer: Add custom Monaco editor themes and a Monaco language for logs. (#69)
1 parent 0ba5cff commit 1d5d95e

File tree

6 files changed

+158
-18
lines changed

6 files changed

+158
-18
lines changed

new-log-viewer/src/components/Editor/MonacoInstance/index.tsx

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,11 @@ import "./index.css";
2323

2424

2525
interface MonacoEditorProps {
26+
actions: ActionType[],
2627
lineNum: number,
2728
text: string,
28-
actions: ActionType[],
29+
themeName: "dark" | "light",
30+
2931
beforeMount?: BeforeMountCallback,
3032
beforeTextUpdate?: BeforeTextUpdateCallback,
3133
onCursorExplicitPosChange: CursorExplicitPosChangeCallback,
@@ -40,9 +42,10 @@ interface MonacoEditorProps {
4042
* the editor.
4143
*
4244
* @param props
45+
* @param props.actions
4346
* @param props.lineNum
4447
* @param props.text
45-
* @param props.actions
48+
* @param props.themeName
4649
* @param props.beforeMount
4750
* @param props.beforeTextUpdate
4851
* @param props.onCursorExplicitPosChange
@@ -52,9 +55,10 @@ interface MonacoEditorProps {
5255
* @return
5356
*/
5457
const MonacoInstance = ({
58+
actions,
5559
lineNum,
5660
text,
57-
actions,
61+
themeName,
5862
beforeMount,
5963
beforeTextUpdate,
6064
onMount,
@@ -98,6 +102,11 @@ const MonacoInstance = ({
98102
onMount,
99103
]);
100104

105+
// On `themeName` update, set the theme in the editor.
106+
useEffect(() => {
107+
monaco.editor.setTheme(themeName);
108+
}, [themeName]);
109+
101110
// On `text` update, set the text and position cursor in the editor.
102111
useEffect(() => {
103112
if (null === editorRef.current) {
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import * as monaco from "monaco-editor/esm/vs/editor/editor.api.js";
2+
3+
import {TOKEN_NAME} from "./typings";
4+
5+
6+
const LOG_LANGUAGE_NAME = "logLanguage";
7+
8+
9+
/**
10+
* Registers a custom log language in the Monaco editor.
11+
*/
12+
const setupCustomLogLanguage = () => {
13+
monaco.languages.register({
14+
id: LOG_LANGUAGE_NAME,
15+
});
16+
monaco.languages.setMonarchTokensProvider(LOG_LANGUAGE_NAME, {
17+
tokenizer: {
18+
root: [
19+
[
20+
"INFO",
21+
TOKEN_NAME.CUSTOM_INFO,
22+
],
23+
[
24+
"WARN",
25+
TOKEN_NAME.CUSTOM_WARN,
26+
],
27+
[
28+
"ERROR",
29+
TOKEN_NAME.CUSTOM_ERROR,
30+
],
31+
[
32+
"FATAL",
33+
TOKEN_NAME.CUSTOM_FATAL,
34+
],
35+
[
36+
/(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3})Z/,
37+
TOKEN_NAME.CUSTOM_DATE,
38+
],
39+
[
40+
/^[\t ]*at.*$/,
41+
TOKEN_NAME.CUSTOM_EXCEPTION,
42+
],
43+
[
44+
/(\d+(?:\.\d+)?([eE])([+-])[0-9](\.[0-9])?|\d+(?:\.\d+)?)/,
45+
TOKEN_NAME.CUSTOM_NUMBER,
46+
],
47+
],
48+
},
49+
});
50+
};
51+
52+
export {
53+
LOG_LANGUAGE_NAME,
54+
setupCustomLogLanguage,
55+
};
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import * as monaco from "monaco-editor/esm/vs/editor/editor.api.js";
2+
3+
import {THEME_NAME} from "../../../typings/config";
4+
import {TOKEN_NAME} from "./typings";
5+
6+
7+
/**
8+
* Sets up custom themes for the Monaco editor.
9+
*/
10+
const setupThemes = () => {
11+
monaco.editor.defineTheme(THEME_NAME.DARK, {
12+
base: "vs-dark",
13+
inherit: true,
14+
rules: [
15+
{token: TOKEN_NAME.CUSTOM_INFO, foreground: "#098658"},
16+
{token: TOKEN_NAME.CUSTOM_WARN, foreground: "#ce9178"},
17+
{token: TOKEN_NAME.CUSTOM_ERROR, foreground: "#ce9178", fontStyle: "bold"},
18+
{token: TOKEN_NAME.CUSTOM_FATAL, foreground: "#ce9178", fontStyle: "bold"},
19+
{token: TOKEN_NAME.CUSTOM_DATE, foreground: "#529955"},
20+
{token: TOKEN_NAME.CUSTOM_EXCEPTION, foreground: "#ce723b", fontStyle: "italic"},
21+
{token: TOKEN_NAME.CUSTOM_NUMBER, foreground: "#3f9ccb"},
22+
{token: TOKEN_NAME.COMMENT, foreground: "#008000"},
23+
],
24+
colors: {
25+
"editor.lineHighlightBackground": "#3c3c3c",
26+
},
27+
});
28+
monaco.editor.defineTheme(THEME_NAME.LIGHT, {
29+
base: "vs",
30+
inherit: true,
31+
rules: [
32+
{token: TOKEN_NAME.CUSTOM_INFO, foreground: "#098658"},
33+
{token: TOKEN_NAME.CUSTOM_WARN, foreground: "#b81560"},
34+
{token: TOKEN_NAME.CUSTOM_ERROR, foreground: "#ac1515", fontStyle: "bold"},
35+
{token: TOKEN_NAME.CUSTOM_FATAL, foreground: "#ac1515", fontStyle: "bold"},
36+
{token: TOKEN_NAME.CUSTOM_DATE, foreground: "#008000"},
37+
{token: TOKEN_NAME.CUSTOM_EXCEPTION, foreground: "#ce723b", fontStyle: "italic"},
38+
{token: TOKEN_NAME.CUSTOM_NUMBER, foreground: "#3f9ccb"},
39+
],
40+
colors: {},
41+
});
42+
};
43+
44+
45+
export {setupThemes};

new-log-viewer/src/components/Editor/MonacoInstance/typings.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,17 @@ import * as monaco from "monaco-editor/esm/vs/editor/editor.api.js";
77
import {ACTION_NAME} from "../../../utils/actions";
88

99

10+
enum TOKEN_NAME {
11+
CUSTOM_INFO = "customInfo",
12+
CUSTOM_WARN = "customWarn",
13+
CUSTOM_ERROR = "customError",
14+
CUSTOM_FATAL = "customFatal",
15+
CUSTOM_DATE = "customDate",
16+
CUSTOM_EXCEPTION = "customException",
17+
CUSTOM_NUMBER = "customNumber",
18+
COMMENT = "comment",
19+
}
20+
1021
/**
1122
* Gets called when the cursor position is explicitly changed in the editor.
1223
*
@@ -55,6 +66,7 @@ interface CustomMonacoEditorHandlers {
5566
onCustomAction?: CustomActionCallback,
5667
}
5768

69+
export {TOKEN_NAME};
5870
export type {
5971
BeforeMountCallback,
6072
BeforeTextUpdateCallback,

new-log-viewer/src/components/Editor/MonacoInstance/utils.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ import {
77
setupFocusOnBacktickDown,
88
setupMobileZoom,
99
} from "./actions";
10+
import {
11+
LOG_LANGUAGE_NAME,
12+
setupCustomLogLanguage,
13+
} from "./language";
14+
import {setupThemes} from "./theme";
1015
import {CustomMonacoEditorHandlers} from "./typings";
1116

1217

@@ -38,12 +43,16 @@ const createMonacoEditor = (
3843
actions: ActionType[],
3944
handlers: CustomMonacoEditorHandlers
4045
): monaco.editor.IStandaloneCodeEditor => {
46+
setupCustomLogLanguage();
47+
setupThemes();
48+
4149
const editor = monaco.editor.create(
4250
editorContainer,
4351
{
4452
// eslint-disable-next-line no-warning-comments
4553
// TODO: Add custom observer to debounce automatic layout
4654
automaticLayout: true,
55+
language: LOG_LANGUAGE_NAME,
4756
maxTokenizationLineLength: 30_000,
4857
mouseWheelZoom: true,
4958
readOnly: true,

new-log-viewer/src/components/Editor/index.tsx

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,18 @@ import {
88

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

11+
import {useColorScheme} from "@mui/joy";
12+
1113
import {StateContext} from "../../contexts/StateContextProvider";
1214
import {
1315
updateWindowUrlHashParams,
1416
UrlContext,
1517
} from "../../contexts/UrlContextProvider";
1618
import {Nullable} from "../../typings/common";
17-
import {CONFIG_KEY} from "../../typings/config";
19+
import {
20+
CONFIG_KEY,
21+
THEME_NAME,
22+
} from "../../typings/config";
1823
import {BeginLineNumToLogEventNumMap} from "../../typings/worker";
1924
import {
2025
ACTION_NAME,
@@ -36,12 +41,28 @@ import {goToPositionAndCenter} from "./MonacoInstance/utils";
3641
import "./index.css";
3742

3843

44+
/**
45+
* Resets the cached page size in case it causes a client OOM. If it doesn't, the saved value
46+
* will be restored when {@link restoreCachedPageSize} is called.
47+
*/
48+
const resetCachedPageSize = () => {
49+
const error = setConfig(
50+
{key: CONFIG_KEY.PAGE_SIZE, value: CONFIG_DEFAULT[CONFIG_KEY.PAGE_SIZE]}
51+
);
52+
53+
if (null !== error) {
54+
console.error(`Unexpected error returned by setConfig(): ${error}`);
55+
}
56+
};
57+
3958
/**
4059
* Renders a read-only editor for viewing logs.
4160
*
4261
* @return
4362
*/
4463
const Editor = () => {
64+
const {mode, systemMode} = useColorScheme();
65+
4566
const {beginLineNumToLogEventNum, logData, numEvents} = useContext(StateContext);
4667
const {logEventNum} = useContext(UrlContext);
4768

@@ -100,20 +121,6 @@ const Editor = () => {
100121
});
101122
}, []);
102123

103-
/**
104-
* Resets the cached page size in case it causes a client OOM. If it doesn't, the saved value
105-
* will be restored when {@link restoreCachedPageSize} is called.
106-
*/
107-
const resetCachedPageSize = useCallback(() => {
108-
const error = setConfig(
109-
{key: CONFIG_KEY.PAGE_SIZE, value: CONFIG_DEFAULT[CONFIG_KEY.PAGE_SIZE]}
110-
);
111-
112-
if (null !== error) {
113-
console.error(`Unexpected error returned by setConfig(): ${error}`);
114-
}
115-
}, []);
116-
117124
/**
118125
* Restores the cached page size that was unset in {@link resetCachedPageSize};
119126
*/
@@ -192,6 +199,9 @@ const Editor = () => {
192199
beforeTextUpdate={resetCachedPageSize}
193200
lineNum={lineNum}
194201
text={logData}
202+
themeName={(("system" === mode) ?
203+
systemMode :
204+
mode) ?? THEME_NAME.DARK}
195205
onCursorExplicitPosChange={handleCursorExplicitPosChange}
196206
onCustomAction={handleEditorCustomAction}
197207
onMount={handleMount}

0 commit comments

Comments
 (0)