80 lines
2.9 KiB
TypeScript
80 lines
2.9 KiB
TypeScript
import { StreamLanguage } from '@codemirror/language'
|
|
|
|
/** Nunjucks block comment {# ... #} */
|
|
function tokenNunjucksComment(stream: { match: (re: RegExp) => string | null; next: () => string; eol: () => boolean }) {
|
|
if (stream.match(/^\{#/)) {
|
|
while (!stream.eol()) {
|
|
if (stream.match(/#\}/)) return 'comment'
|
|
stream.next()
|
|
}
|
|
return 'comment'
|
|
}
|
|
return null
|
|
}
|
|
|
|
/** Nunjucks variable {{ ... }} or tag {% ... %} - tokenize the whole block */
|
|
function tokenNunjucksBlock(stream: { match: (re: RegExp) => string | null; next: () => string; eol: () => boolean }) {
|
|
if (stream.match(/^\{\{/)) {
|
|
while (!stream.eol()) {
|
|
if (stream.match(/\}\}/)) return 'variableName.special'
|
|
stream.next()
|
|
}
|
|
return 'variableName.special'
|
|
}
|
|
if (stream.match(/^\{\%/)) {
|
|
while (!stream.eol()) {
|
|
if (stream.match(/%\}/)) return 'keyword'
|
|
stream.next()
|
|
}
|
|
return 'keyword'
|
|
}
|
|
return null
|
|
}
|
|
|
|
/** Simple PlantUML + Nunjucks stream parser for syntax highlighting in CodeMirror */
|
|
const plantumlParser = StreamLanguage.define({
|
|
name: 'plantuml',
|
|
token(stream) {
|
|
// Nunjucks {# ... #} comment
|
|
const nunjucksComment = tokenNunjucksComment(stream)
|
|
if (nunjucksComment) return nunjucksComment
|
|
// Nunjucks {{ }} and {% %}
|
|
const nunjucksBlock = tokenNunjucksBlock(stream)
|
|
if (nunjucksBlock) return nunjucksBlock
|
|
|
|
// Single-quote line comment (PlantUML)
|
|
if (stream.match(/^'/)) {
|
|
stream.skipToEnd()
|
|
return 'comment'
|
|
}
|
|
// Double-quoted string
|
|
if (stream.match(/^"/)) {
|
|
let escaped = false
|
|
while (!stream.eol()) {
|
|
if (escaped) {
|
|
escaped = false
|
|
stream.next()
|
|
continue
|
|
}
|
|
const ch = stream.next()
|
|
if (ch === '\\') escaped = true
|
|
else if (ch === '"') break
|
|
}
|
|
return 'string'
|
|
}
|
|
// @directives (@startuml, @enduml, etc.)
|
|
if (stream.match(/^@\w+/)) return 'meta'
|
|
// Skip whitespace
|
|
if (stream.eatSpace()) return null
|
|
// Arrows and connectors
|
|
if (stream.match(/^->>?|<-<?|-->>?|<<--?|<-?>/)) return 'keyword'
|
|
// Keywords (participant, actor, as, title, etc.)
|
|
if (stream.match(/^(participant|actor|as|title|autonumber|left|right|of|over|activate|deactivate|destroy|create|group|opt|alt|else|loop|par|end|note|legend|skinparam|start|stop|if|endif|elseif|while|endwhile|repeat|until|switch|case|endswitch|class|interface|enum|package|namespace|abstract|static|extends|implements)\b/i)) return 'keyword'
|
|
// Any other character (identifier, punctuation, etc.)
|
|
stream.next()
|
|
return null
|
|
},
|
|
})
|
|
|
|
export const plantumlLanguage = plantumlParser
|