import type { languages } from 'monaco-editor'; // Build regex patterns for each keyword category. // Longer patterns must come first so alternation prefers them. const pipelinePattern = 'json|logfmt|regexp|pattern|unpack|line_format|label_format|drop|keep|unwrap|decolorize'; const rangeFuncPattern = 'rate_counter|count_over_time|bytes_rate|bytes_over_time|' + 'sum_over_time|avg_over_time|max_over_time|min_over_time|' + 'first_over_time|last_over_time|stdvar_over_time|stddev_over_time|' + 'quantile_over_time|absent_over_time|rate'; const aggrPattern = 'sort_desc|approx_topk|stddev|stdvar|bottomk|topk|sum|avg|min|max|count|sort'; const otherPattern = 'group_left|group_right|without|ignoring|offset|bool|vector|by|and|or|on'; export function buildMonarchLanguage(): languages.IMonarchLanguage { return { defaultToken: '', tokenPostfix: '.loki', brackets: [ { open: '{', close: '}', token: 'delimiter.curly' }, { open: '[', close: ']', token: 'delimiter.square' }, { open: '(', close: ')', token: 'delimiter.parenthesis' }, ], tokenizer: { root: [ // Whitespace [/[ \t\r\n]+/, 'white'], // Comments: # [/#.*$/, 'comment'], // Strings [/"/, { token: 'string.quote', next: '@string_double' }], [/'/, { token: 'string.quote', next: '@string_single' }], [/`/, { token: 'string.quote', next: '@string_backtick' }], // Duration [/\d+(?:\.\d+)?(?:ns|us|µs|ms|s|m|h)\b/, 'type.duration'], // Bytes [/\d+(?:\.\d+)?(?:B|kB|MB|GB|TB|KB|KiB|MiB|GiB|TiB)\b/, 'type.bytes'], // Numbers [/\d+\.\d+/, 'number.float'], [/\d+/, 'number'], // Operators (order matters: longer patterns first) [/!=/, 'operator'], [/!~/, 'operator'], [/=~/, 'operator'], [/>=/, 'operator'], [/<=/, 'operator'], [/==/, 'operator'], [/[=<>]/, 'operator'], // Pipe operators [/\|~/, 'operator.pipe'], [/\|=/, 'operator.pipe'], [/\|/, 'operator.pipe'], // Brackets and punctuation [/\{/, 'delimiter.curly'], [/\}/, 'delimiter.curly'], [/\[/, 'delimiter.square'], [/\]/, 'delimiter.square'], [/\(/, 'delimiter.parenthesis'], [/\)/, 'delimiter.parenthesis'], [/,/, 'delimiter.comma'], // Keywords (must come before generic identifier) [new RegExp('\\b(?:' + pipelinePattern + ')\\b'), 'keyword.pipeline'], [new RegExp('\\b(?:' + rangeFuncPattern + ')\\b'), 'keyword.function'], [new RegExp('\\b(?:' + aggrPattern + ')\\b'), 'keyword.aggregation'], [new RegExp('\\b(?:' + otherPattern + ')\\b'), 'keyword'], // Generic identifier [/[a-zA-Z_][\w]*/, 'identifier'], // Catch-all [/[;:]/, 'delimiter'], ], string_double: [ [/[^\\"]+/, 'string'], [/\\./, 'string.escape'], [/"/, { token: 'string.quote', next: '@pop' }], ], string_single: [ [/[^\\']+/, 'string'], [/\\./, 'string.escape'], [/'/, { token: 'string.quote', next: '@pop' }], ], string_backtick: [ [/[^`]+/, 'string'], [/`/, { token: 'string.quote', next: '@pop' }], ], }, } as languages.IMonarchLanguage; }