diff --git a/src/components/EditorTextArea.tsx b/src/components/EditorTextArea.tsx index 4a7630a..d4cdde1 100644 --- a/src/components/EditorTextArea.tsx +++ b/src/components/EditorTextArea.tsx @@ -17,6 +17,7 @@ import themes, { Theme } from '../style/themes'; import type { editor } from 'monaco-editor'; import { ResetFunction } from './Editor'; +import { logLanguage } from '../util/log-language'; export interface EditorTextAreaProps { forcedContent: string; @@ -60,6 +61,9 @@ export default function EditorTextArea({ monaco.editor.defineTheme(theme.id, theme.editor); } + monaco.languages.register({ id: 'log' }); + monaco.languages.setMonarchTokensProvider('log', logLanguage); + monaco.languages.typescript.typescriptDefaults.setDiagnosticsOptions({ noSemanticValidation: true, noSyntaxValidation: true, diff --git a/src/style/themes.ts b/src/style/themes.ts index d390066..28d2c68 100644 --- a/src/style/themes.ts +++ b/src/style/themes.ts @@ -59,6 +59,11 @@ const themes: Themes = { keyword: '#ff7b72', type: '#ffa657', variable: '#ffa657', + logInfo: '#3fb950', // green.3 + logError: '#f85149', // red.4 + logWarning: '#d29922', // yellow.3 + logDate: '#33B3AE', // teal.3 + logException: '#f8e3a1', // yellow.0 }, }), }, @@ -90,6 +95,11 @@ const themes: Themes = { keyword: '#0077aa', type: '#DD4A68', variable: '#ee9900', + logInfo: '#2da44e', // green.4 + logError: '#cf222e', // red.5 + logWarning: '#d4a72c', // yellow.3 + logDate: '#136061', // teal.6 + logException: '#7d4e00', // yellow.6 }, }), }, @@ -104,7 +114,13 @@ const themes: Themes = { color: '#586e75', backgroundColor: '#44475a', }, - editor: dracula as editor.IStandaloneThemeData, + editor: addLogColors(dracula as editor.IStandaloneThemeData, { + info: '#50FA7B', // green + error: '#FF5555', // red + warning: '#FFB86C', // orange + date: '#BD93F9', // purple + exception: '#F1FA8C', // yellow + }), }, 'monokai': { id: 'monokai', @@ -117,7 +133,13 @@ const themes: Themes = { color: '#49483E', backgroundColor: '#3E3D32', }, - editor: monokai as editor.IStandaloneThemeData, + editor: addLogColors(monokai as editor.IStandaloneThemeData, { + info: '#a6e22e', // green + error: '#f92672', // red + warning: '#fd971f', // orange + date: '#AB9DF2', // purple + exception: '#F1FA8C', // yellow + }), }, 'solarized': { id: 'solarized', @@ -130,7 +152,13 @@ const themes: Themes = { color: '#93a1a1', // base1 backgroundColor: '#073642', // base02 }, - editor: solarizedDark as editor.IStandaloneThemeData, + editor: addLogColors(solarizedDark as editor.IStandaloneThemeData, { + info: '#268bd2', // blue + error: '#dc322f', // red + warning: '#b58900', // yellow + date: '#2aa198', // cyan + exception: '#859900', // green + }), }, 'solarized-light': { id: 'solarized-light', @@ -143,7 +171,13 @@ const themes: Themes = { color: '#586e75', // base01 backgroundColor: '#eee8d5', // base2 }, - editor: solarizedLight as editor.IStandaloneThemeData, + editor: addLogColors(solarizedLight as editor.IStandaloneThemeData, { + info: '#268bd2', // blue + error: '#dc322f', // red + warning: '#b58900', // yellow + date: '#2aa198', // cyan + exception: '#859900', // green + }), }, }; @@ -164,6 +198,11 @@ interface MonacoThemeProps { keyword: Color; type: Color; variable: Color; + logInfo: Color; + logError: Color; + logWarning: Color; + logDate: Color; + logException: Color; }; } @@ -202,6 +241,11 @@ export function makeMonacoTheme( { token: 'identifier', foreground: colors.primary }, { token: 'type', foreground: colors.type }, { token: 'comment', foreground: colors.comment }, + { token: 'info.log', foreground: colors.logInfo }, + { token: 'error.log', foreground: colors.logError, fontStyle: 'bold' }, + { token: 'warning.log', foreground: colors.logWarning }, + { token: 'date.log', foreground: colors.logDate }, + { token: 'exception.log', foreground: colors.logException }, ], colors: { 'editor.background': `#${colors.background}`, @@ -209,3 +253,30 @@ export function makeMonacoTheme( }, }; } + +interface LogColors { + info: Color; + error: Color; + warning: Color; + date: Color; + exception: Color; +} + +export function addLogColors( + theme: editor.IStandaloneThemeData, + logColors: LogColors +): editor.IStandaloneThemeData { + const colors = Object.fromEntries( + Object.entries(logColors).map(([key, color]) => [key, color.substring(1)]) + ) as Record; + theme.rules.push( + ...[ + { token: 'info.log', foreground: colors.info }, + { token: 'error.log', foreground: colors.error, fontStyle: 'bold' }, + { token: 'warning.log', foreground: colors.warning }, + { token: 'date.log', foreground: colors.date }, + { token: 'exception.log', foreground: colors.exception }, + ] + ); + return theme; +} diff --git a/src/util/highlighting.ts b/src/util/highlighting.ts index d02dddc..c6a3879 100644 --- a/src/util/highlighting.ts +++ b/src/util/highlighting.ts @@ -1,4 +1,5 @@ export const languages = { + text: ['plain', 'log'], config: ['yaml', 'json', 'xml', 'ini'], code: [ 'java', @@ -6,6 +7,7 @@ export const languages = { 'typescript', 'python', 'kotlin', + 'scala', 'cpp', 'csharp', 'shell', @@ -14,11 +16,8 @@ export const languages = { 'sql', 'go', ], - web: ['html', 'css', 'php'], - misc: ['plain', 'dockerfile', 'markdown'], + web: ['html', 'css', 'scss', 'php', 'graphql'], + misc: ['dockerfile', 'markdown', 'proto'], }; -// missing following the rewrite: toml, properties, log, javastacktrace, groovy, haskell, protobuf -// would be good to add these back with custom language definitions - export const languageIds = Object.values(languages).flat(1); diff --git a/src/util/log-language.ts b/src/util/log-language.ts new file mode 100644 index 0000000..33dd322 --- /dev/null +++ b/src/util/log-language.ts @@ -0,0 +1,71 @@ +import type { languages } from 'monaco-editor'; + +// Source: +// - https://github.com/emilast/vscode-logfile-highlighter/blob/master/syntaxes/log.tmLanguage +// - https://github.com/sumy7/monaco-language-log/blob/main/language-log.js +export const logLanguage: languages.IMonarchLanguage = { + defaultToken: '', + tokenizer: { + // prettier-ignore + root: [ + // Trace/Verbose + [/\b(Trace)\b:/, 'verbose'], + // Serilog VERBOSE + [/\[(verbose|verb|vrb|vb|v)]/i, 'verbose'], + // Android logcat Verbose + [/\bV\//, 'verbose'], + // DEBUG + [/\b(DEBUG|Debug)\b|\b([dD][eE][bB][uU][gG]):/, 'debug'], + // Serilog DEBUG + [/\[(debug|dbug|dbg|de|d)]/i, 'debug'], + // Android logcat Debug + [/\bD\//, 'debug'], + // INFO + [/\b(HINT|INFO|INFORMATION|Info|NOTICE|II)\b|\b([iI][nN][fF][oO]|[iI][nN][fF][oO][rR][mM][aA][tT][iI][oO][nN]):/, 'info'], + // serilog INFO + [/\[(information|info|inf|in|i)]/i, 'info'], + // Android logcat Info + [/\bI\//, 'info'], + // WARN + [/\b(WARNING|WARN|Warn|WW)\b|\b([wW][aA][rR][nN][iI][nN][gG]):/, 'warning'], + // Serilog WARN + [/\[(warning|warn|wrn|wn|w)]/i, 'warning'], + // Android logcat Warning + [/\bW\//, 'warning'], + // ERROR + [/\b(ALERT|CRITICAL|EMERGENCY|ERROR|FAILURE|FAIL|Fatal|FATAL|Error|EE)\b|\b([eE][rR][rR][oO][rR]):/, 'error'], + // Serilog ERROR + [/\[(error|eror|err|er|e|fatal|fatl|ftl|fa|f)]/i, 'error'], + // Android logcat Error + [/\bE\//, 'error'], + // ISO dates ("2020-01-01") + [/\b\d{4}-\d{2}-\d{2}(T|\b)/, 'date'], + // Culture specific dates ("01/01/2020", "01.01.2020") + [/\b\d{2}[^\w\s]\d{2}[^\w\s]\d{4}\b/, 'date'], + // Clock times with optional timezone ("01:01:01", "01:01:01.001", "01:01:01+01:01") + [/\d{1,2}:\d{2}(:\d{2}([.,]\d{1,})?)?(Z| ?[+-]\d{1,2}:\d{2})?\b/, 'date'], + // Git commit hashes of length 40, 10, or 7 + //[/\b([0-9a-fA-F]{40}|[0-9a-fA-F]{10}|[0-9a-fA-F]{7})\b/, 'constant'], + // Guids + [/[0-9a-fA-F]{8}[-]?([0-9a-fA-F]{4}[-]?){3}[0-9a-fA-F]{12}/, 'constant'], + // MAC addresses: 89:A1:23:45:AB:C0, fde8:e767:269c:0:9425:3477:7c8f:7f1a + //[/\b([0-9a-fA-F]{2,}[:-])+([0-9a-fA-F]{2,})+\b/, 'constant'], + // Constants + //[/\b([0-9]+|true|false|null)\b/, 'constant'], + // Hex Constants + [/\b(0x[a-fA-F0-9]+)\b/, 'constant'], + // String constants + [/"[^"]*"/, 'string'], + [/(?