Copy template engine from ktor
This commit is contained in:
@@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.kdoc
|
||||||
|
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A template that expands inside [TOuter]
|
||||||
|
*/
|
||||||
|
interface Template<in TOuter> {
|
||||||
|
fun TOuter.apply()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A placeholder that is inserted inside [TOuter]
|
||||||
|
*/
|
||||||
|
open class Placeholder<TOuter> {
|
||||||
|
private var contentStack = mutableListOf<(TOuter.(Placeholder<TOuter>.Exec) -> Unit)>()
|
||||||
|
|
||||||
|
var meta: String = ""
|
||||||
|
|
||||||
|
operator fun invoke(meta: String = "", content: TOuter.(Placeholder<TOuter>.Exec) -> Unit) {
|
||||||
|
this.contentStack.add(content)
|
||||||
|
this.meta = meta
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class Exec(var depth: Int, val outer: TOuter) {
|
||||||
|
|
||||||
|
fun inherit() {
|
||||||
|
depth--
|
||||||
|
contentStack.getOrNull(depth)?.invoke(outer, this@Exec)
|
||||||
|
depth++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isEmpty() = contentStack.isEmpty()
|
||||||
|
|
||||||
|
fun apply(destination: TOuter) {
|
||||||
|
val top = contentStack.lastOrNull()
|
||||||
|
val exec = Exec(contentStack.lastIndex, destination)
|
||||||
|
top?.invoke(destination, exec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Placeholder that can appear multiple times
|
||||||
|
*/
|
||||||
|
open class PlaceholderList<TOuter, TInner>() {
|
||||||
|
private var items = ArrayList<PlaceholderItem<TInner>>()
|
||||||
|
operator fun invoke(meta: String = "", content: TInner.(Placeholder<TInner>.Exec) -> Unit = {}) {
|
||||||
|
val placeholder = PlaceholderItem<TInner>(items.size, items)
|
||||||
|
placeholder(meta, content)
|
||||||
|
items.add(placeholder)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isEmpty(): Boolean = items.size == 0
|
||||||
|
fun apply(destination: TOuter, render: TOuter.(PlaceholderItem<TInner>) -> Unit) {
|
||||||
|
for (item in items) {
|
||||||
|
destination.render(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Item of a placeholder list when it is expanded
|
||||||
|
*/
|
||||||
|
class PlaceholderItem<TOuter>(val index: Int, val collection: List<PlaceholderItem<TOuter>>) : Placeholder<TOuter>() {
|
||||||
|
val first: Boolean get() = index == 0
|
||||||
|
val last: Boolean get() = index == collection.lastIndex
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts every element of placeholder list
|
||||||
|
*/
|
||||||
|
fun <TOuter, TInner> TOuter.each(items: PlaceholderList<TOuter, TInner>, itemTemplate: TOuter.(PlaceholderItem<TInner>) -> Unit): Unit {
|
||||||
|
items.apply(this, itemTemplate)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts placeholder
|
||||||
|
*/
|
||||||
|
fun <TOuter> TOuter.insert(placeholder: Placeholder<TOuter>): Unit = placeholder.apply(this)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A placeholder that is also a template
|
||||||
|
*/
|
||||||
|
open class TemplatePlaceholder<TTemplate> {
|
||||||
|
private var content: TTemplate.() -> Unit = { }
|
||||||
|
operator fun invoke(content: TTemplate.() -> Unit) {
|
||||||
|
this.content = content
|
||||||
|
}
|
||||||
|
|
||||||
|
fun apply(template: TTemplate) {
|
||||||
|
template.content()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <TTemplate : Template<TOuter>, TOuter> TOuter.insert(template: TTemplate, placeholder: TemplatePlaceholder<TTemplate>) {
|
||||||
|
placeholder.apply(template)
|
||||||
|
with (template) { apply() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <TOuter, TTemplate : Template<TOuter>> TOuter.insert(template: TTemplate, build: TTemplate.() -> Unit) {
|
||||||
|
template.build()
|
||||||
|
with (template) { apply() }
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user