-
Notifications
You must be signed in to change notification settings - Fork 5
/
liquid.ts
94 lines (88 loc) · 3.49 KB
/
liquid.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import {Language, LRLanguage, LanguageSupport, foldNodeProp,
indentNodeProp, delimitedIndent, TreeIndentContext} from "@codemirror/language"
import {html} from "@codemirror/lang-html"
import {styleTags, tags as t} from "@lezer/highlight"
import {parseMixed} from "@lezer/common"
import {parser} from "./liquid.grammar"
import {liquidCompletionSource, LiquidCompletionConfig, closePercentBrace} from "./complete"
export {liquidCompletionSource, LiquidCompletionConfig, closePercentBrace}
function directiveIndent(except: RegExp) {
return (context: TreeIndentContext) => {
let back = except.test(context.textAfter)
return context.lineIndent(context.node.from) + (back ? 0 : context.unit)
}
}
const tagLanguage = LRLanguage.define({
name: "liquid",
parser: parser.configure({
props: [
styleTags({
"cycle comment endcomment raw endraw echo increment decrement liquid in with as": t.keyword,
"empty forloop tablerowloop": t.atom,
"if elsif else endif unless endunless case endcase for endfor tablerow endtablerow break continue": t.controlKeyword,
"assign capture endcapture": t.definitionKeyword,
"contains": t.operatorKeyword,
"render include": t.moduleKeyword,
VariableName: t.variableName,
TagName: t.tagName,
FilterName: t.function(t.variableName),
PropertyName: t.propertyName,
CompareOp: t.compareOperator,
AssignOp: t.definitionOperator,
LogicOp: t.logicOperator,
NumberLiteral: t.number,
StringLiteral: t.string,
BooleanLiteral: t.bool,
InlineComment: t.lineComment,
CommentText: t.blockComment,
"{% %} {{ }}": t.brace,
"( )": t.paren,
".": t.derefOperator,
", .. : |": t.punctuation
}),
indentNodeProp.add({
Tag: delimitedIndent({closing: "%}"}),
"UnlessDirective ForDirective TablerowDirective CaptureDirective":
directiveIndent(/^\s*(\{%-?\s*)?end\w/),
IfDirective: directiveIndent(/^\s*(\{%-?\s*)?(endif|else|elsif)\b/),
CaseDirective: directiveIndent(/^\s*(\{%-?\s*)?(endcase|when)\b/),
}),
foldNodeProp.add({
"UnlessDirective ForDirective TablerowDirective CaptureDirective IfDirective CaseDirective RawDirective Comment"(tree) {
let first = tree.firstChild, last = tree.lastChild!
if (!first || first.name != "Tag") return null
return {from: first.to, to: last.name == "EndTag" ? last.from : tree.to}
}
})
]
}),
languageData: {
commentTokens: {line: "#"},
indentOnInput: /^\s*{%-?\s*(?:end|elsif|else|when|)$/
}
})
const baseHTML = html()
function makeLiquid(base: Language) {
return tagLanguage.configure({
wrap: parseMixed(node => node.type.isTop ? {
parser: base.parser,
overlay: n => n.name == "Text" || n.name == "RawText"
} : null)
}, "liquid")
}
/// A language provider for Liquid templates.
export const liquidLanguage = makeLiquid(baseHTML.language)
/// Liquid template support.
export function liquid(config: LiquidCompletionConfig & {
/// Provide an HTML language configuration to use as a base.
base?: LanguageSupport
} = {}) {
let base = config.base || baseHTML
let lang = base.language == baseHTML.language ? liquidLanguage : makeLiquid(base.language)
return new LanguageSupport(lang, [
base.support,
lang.data.of({autocomplete: liquidCompletionSource(config)}),
base.language.data.of({closeBrackets: {brackets: ["{"]}}),
closePercentBrace
])
}